staging: ft1000-pcmcia: remove PSEUDO_HDR typedefs
[linux-2.6-block.git] / 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 USHORT get_handshake(struct net_device *dev, USHORT expected_value);
90 void put_handshake(struct net_device *dev, USHORT handshake_value);
91 USHORT 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 USHORT hdr_checksum(struct pseudo_hdr *pHdr);
95
96 typedef struct _DSP_FILE_HDR {
97         u32  build_date;
98         u32  dsp_coff_date;
99         u32  loader_code_address;
100         u32  loader_code_size;
101         u32  loader_code_end;
102         u32  dsp_code_address;
103         u32  dsp_code_size;
104         u32  dsp_code_end;
105         u32  reserved[8];
106 } __attribute__ ((packed)) DSP_FILE_HDR, *PDSP_FILE_HDR;
107
108 typedef struct _DSP_FILE_HDR_5 {
109         u32  version_id;        // Version ID of this image format.
110         u32  package_id;        // Package ID of code release.
111         u32  build_date;        // Date/time stamp when file was built.
112         u32  commands_offset;   // Offset to attached commands in Pseudo Hdr format.
113         u32  loader_offset;     // Offset to bootloader code.
114         u32  loader_code_address;       // Start address of bootloader.
115         u32  loader_code_end;   // Where bootloader code ends.
116         u32  loader_code_size;
117         u32  version_data_offset;       // Offset were scrambled version data begins.
118         u32  version_data_size; // Size, in words, of scrambled version data.
119         u32  nDspImages;        // Number of DSP images in file.
120 } __attribute__ ((packed)) DSP_FILE_HDR_5, *PDSP_FILE_HDR_5;
121
122 typedef struct _DSP_IMAGE_INFO {
123         u32  coff_date;         // Date/time when DSP Coff image was built.
124         u32  begin_offset;      // Offset in file where image begins.
125         u32  end_offset;        // Offset in file where image begins.
126         u32  run_address;       // On chip Start address of DSP code.
127         u32  image_size;        // Size of image.
128         u32  version;           // Embedded version # of DSP code.
129 } __attribute__ ((packed)) DSP_IMAGE_INFO, *PDSP_IMAGE_INFO;
130
131 typedef struct _DSP_IMAGE_INFO_V6 {
132         u32  coff_date;         // Date/time when DSP Coff image was built.
133         u32  begin_offset;      // Offset in file where image begins.
134         u32  end_offset;        // Offset in file where image begins.
135         u32  run_address;       // On chip Start address of DSP code.
136         u32  image_size;        // Size of image.
137         u32  version;           // Embedded version # of DSP code.
138         unsigned short checksum;        // Dsp File checksum
139         unsigned short pad1;
140 } __attribute__ ((packed)) DSP_IMAGE_INFO_V6, *PDSP_IMAGE_INFO_V6;
141
142 void card_bootload(struct net_device *dev)
143 {
144         FT1000_INFO *info = (PFT1000_INFO) netdev_priv(dev);
145         unsigned long flags;
146         PULONG pdata;
147         UINT size;
148         UINT i;
149         ULONG templong;
150
151         DEBUG(0, "card_bootload is called\n");
152
153         pdata = (PULONG) bootimage;
154         size = sizeof(bootimage);
155
156         // check for odd word
157         if (size & 0x0003) {
158                 size += 4;
159         }
160         // Provide mutual exclusive access while reading ASIC registers.
161         spin_lock_irqsave(&info->dpram_lock, flags);
162
163         // need to set i/o base address initially and hardware will autoincrement
164         ft1000_write_reg(dev, FT1000_REG_DPRAM_ADDR, FT1000_DPRAM_BASE);
165         // write bytes
166         for (i = 0; i < (size >> 2); i++) {
167                 templong = *pdata++;
168                 outl(templong, dev->base_addr + FT1000_REG_MAG_DPDATA);
169         }
170
171         spin_unlock_irqrestore(&info->dpram_lock, flags);
172 }
173
174 USHORT get_handshake(struct net_device *dev, USHORT expected_value)
175 {
176         FT1000_INFO *info = (PFT1000_INFO) netdev_priv(dev);
177         USHORT handshake;
178         ULONG tempx;
179         int loopcnt;
180
181         loopcnt = 0;
182         while (loopcnt < MAX_DSP_WAIT_LOOPS) {
183                 if (info->AsicID == ELECTRABUZZ_ID) {
184                         ft1000_write_reg(dev, FT1000_REG_DPRAM_ADDR,
185                                          DWNLD_HANDSHAKE_LOC);
186
187                         handshake = ft1000_read_reg(dev, FT1000_REG_DPRAM_DATA);
188                 } else {
189                         tempx =
190                                 ntohl(ft1000_read_dpram_mag_32
191                                   (dev, DWNLD_MAG_HANDSHAKE_LOC));
192                         handshake = (USHORT) tempx;
193                 }
194
195                 if ((handshake == expected_value)
196                         || (handshake == HANDSHAKE_RESET_VALUE)) {
197                         return handshake;
198                 } else {
199                         loopcnt++;
200                         mdelay(DSP_WAIT_SLEEP_TIME);
201                 }
202
203         }
204
205         return HANDSHAKE_TIMEOUT_VALUE;
206
207 }
208
209 void put_handshake(struct net_device *dev, USHORT handshake_value)
210 {
211         FT1000_INFO *info = (PFT1000_INFO) netdev_priv(dev);
212         ULONG tempx;
213
214         if (info->AsicID == ELECTRABUZZ_ID) {
215                 ft1000_write_reg(dev, FT1000_REG_DPRAM_ADDR,
216                                  DWNLD_HANDSHAKE_LOC);
217                 ft1000_write_reg(dev, FT1000_REG_DPRAM_DATA, handshake_value);  /* Handshake */
218         } else {
219                 tempx = (ULONG) handshake_value;
220                 tempx = ntohl(tempx);
221                 ft1000_write_dpram_mag_32(dev, DWNLD_MAG_HANDSHAKE_LOC, tempx); /* Handshake */
222         }
223 }
224
225 USHORT get_request_type(struct net_device *dev)
226 {
227         FT1000_INFO *info = (PFT1000_INFO) netdev_priv(dev);
228         USHORT request_type;
229         ULONG tempx;
230
231         if (info->AsicID == ELECTRABUZZ_ID) {
232                 ft1000_write_reg(dev, FT1000_REG_DPRAM_ADDR, DWNLD_TYPE_LOC);
233                 request_type = ft1000_read_reg(dev, FT1000_REG_DPRAM_DATA);
234         } else {
235                 tempx = ft1000_read_dpram_mag_32(dev, DWNLD_MAG_TYPE_LOC);
236                 tempx = ntohl(tempx);
237                 request_type = (USHORT) tempx;
238         }
239
240         return request_type;
241
242 }
243
244 long get_request_value(struct net_device *dev)
245 {
246         FT1000_INFO *info = (PFT1000_INFO) netdev_priv(dev);
247         long value;
248         USHORT w_val;
249
250         if (info->AsicID == ELECTRABUZZ_ID) {
251                 ft1000_write_reg(dev, FT1000_REG_DPRAM_ADDR,
252                                  DWNLD_SIZE_MSW_LOC);
253
254                 w_val = ft1000_read_reg(dev, FT1000_REG_DPRAM_DATA);
255
256                 value = (long)(w_val << 16);
257
258                 ft1000_write_reg(dev, FT1000_REG_DPRAM_ADDR,
259                                  DWNLD_SIZE_LSW_LOC);
260
261                 w_val = ft1000_read_reg(dev, FT1000_REG_DPRAM_DATA);
262
263                 value = (long)(value | w_val);
264         } else {
265                 value = ft1000_read_dpram_mag_32(dev, DWNLD_MAG_SIZE_LOC);
266                 value = ntohl(value);
267         }
268
269         return value;
270
271 }
272
273 void put_request_value(struct net_device *dev, long lvalue)
274 {
275         FT1000_INFO *info = (PFT1000_INFO) netdev_priv(dev);
276         USHORT size;
277         ULONG tempx;
278
279         if (info->AsicID == ELECTRABUZZ_ID) {
280                 size = (USHORT) (lvalue >> 16);
281
282                 ft1000_write_reg(dev, FT1000_REG_DPRAM_ADDR,
283                                  DWNLD_SIZE_MSW_LOC);
284
285                 ft1000_write_reg(dev, FT1000_REG_DPRAM_DATA, size);
286
287                 size = (USHORT) (lvalue);
288
289                 ft1000_write_reg(dev, FT1000_REG_DPRAM_ADDR,
290                                  DWNLD_SIZE_LSW_LOC);
291
292                 ft1000_write_reg(dev, FT1000_REG_DPRAM_DATA, size);
293         } else {
294                 tempx = ntohl(lvalue);
295                 ft1000_write_dpram_mag_32(dev, DWNLD_MAG_SIZE_LOC, tempx);      /* Handshake */
296         }
297
298 }
299
300 USHORT hdr_checksum(struct pseudo_hdr *pHdr)
301 {
302         USHORT *usPtr = (USHORT *) pHdr;
303         USHORT chksum;
304
305         chksum = ((((((usPtr[0] ^ usPtr[1]) ^ usPtr[2]) ^ usPtr[3]) ^
306                         usPtr[4]) ^ usPtr[5]) ^ usPtr[6]);
307
308         return chksum;
309 }
310
311 int card_download(struct net_device *dev, const u8 *pFileStart, UINT FileLength)
312 {
313         FT1000_INFO *info = (PFT1000_INFO) netdev_priv(dev);
314         int Status = SUCCESS;
315         USHORT DspWordCnt = 0;
316         UINT uiState;
317         USHORT handshake;
318         struct pseudo_hdr *pHdr;
319         USHORT usHdrLength;
320         PDSP_FILE_HDR pFileHdr;
321         long word_length;
322         USHORT request;
323         USHORT temp;
324         PPROV_RECORD pprov_record;
325         PUCHAR pbuffer;
326         PDSP_FILE_HDR_5 pFileHdr5;
327         PDSP_IMAGE_INFO pDspImageInfo = NULL;
328         PDSP_IMAGE_INFO_V6 pDspImageInfoV6 = NULL;
329         long requested_version;
330         BOOLEAN bGoodVersion = 0;
331         PDRVMSG pMailBoxData;
332         USHORT *pUsData = NULL;
333         USHORT *pUsFile = NULL;
334         UCHAR *pUcFile = NULL;
335         UCHAR *pBootEnd = NULL;
336         UCHAR *pCodeEnd = NULL;
337         int imageN;
338         long file_version;
339         long loader_code_address = 0;
340         long loader_code_size = 0;
341         long run_address = 0;
342         long run_size = 0;
343         unsigned long flags;
344         unsigned long templong;
345         unsigned long image_chksum = 0;
346
347         //
348         // Get version id of file, at first 4 bytes of file, for newer files.
349         //
350         file_version = *(long *)pFileStart;
351
352         uiState = STATE_START_DWNLD;
353
354         pFileHdr = (PDSP_FILE_HDR) pFileStart;
355         pFileHdr5 = (PDSP_FILE_HDR_5) pFileStart;
356
357         switch (file_version) {
358         case 5:
359         case 6:
360                 pUsFile =
361                         (USHORT *) ((long)pFileStart + pFileHdr5->loader_offset);
362                 pUcFile =
363                         (UCHAR *) ((long)pFileStart + pFileHdr5->loader_offset);
364
365                 pBootEnd =
366                         (UCHAR *) ((long)pFileStart + pFileHdr5->loader_code_end);
367
368                 loader_code_address = pFileHdr5->loader_code_address;
369                 loader_code_size = pFileHdr5->loader_code_size;
370                 bGoodVersion = FALSE;
371                 break;
372
373         default:
374                 Status = FAILURE;
375                 break;
376         }
377
378         while ((Status == SUCCESS) && (uiState != STATE_DONE_FILE)) {
379
380                 switch (uiState) {
381                 case STATE_START_DWNLD:
382
383                         handshake = get_handshake(dev, HANDSHAKE_DSP_BL_READY);
384
385                         if (handshake == HANDSHAKE_DSP_BL_READY) {
386                                 put_handshake(dev, HANDSHAKE_DRIVER_READY);
387                         } else {
388                                 Status = FAILURE;
389                         }
390
391                         uiState = STATE_BOOT_DWNLD;
392
393                         break;
394
395                 case STATE_BOOT_DWNLD:
396                         handshake = get_handshake(dev, HANDSHAKE_REQUEST);
397                         if (handshake == HANDSHAKE_REQUEST) {
398                                 /*
399                                  * Get type associated with the request.
400                                  */
401                                 request = get_request_type(dev);
402                                 switch (request) {
403                                 case REQUEST_RUN_ADDRESS:
404                                         put_request_value(dev,
405                                                           loader_code_address);
406                                         break;
407                                 case REQUEST_CODE_LENGTH:
408                                         put_request_value(dev,
409                                                           loader_code_size);
410                                         break;
411                                 case REQUEST_DONE_BL:
412                                         /* Reposition ptrs to beginning of code section */
413                                         pUsFile = (USHORT *) ((long)pBootEnd);
414                                         pUcFile = (UCHAR *) ((long)pBootEnd);
415                                         uiState = STATE_CODE_DWNLD;
416                                         break;
417                                 case REQUEST_CODE_SEGMENT:
418                                         word_length = get_request_value(dev);
419                                         if (word_length > MAX_LENGTH) {
420                                                 Status = FAILURE;
421                                                 break;
422                                         }
423                                         if ((word_length * 2 + (long)pUcFile) >
424                                                 (long)pBootEnd) {
425                                                 /*
426                                                  * Error, beyond boot code range.
427                                                  */
428                                                 Status = FAILURE;
429                                                 break;
430                                         }
431                                         // Provide mutual exclusive access while reading ASIC registers.
432                                         spin_lock_irqsave(&info->dpram_lock,
433                                                           flags);
434                                         if (file_version == 5) {
435                                                 /*
436                                                  * Position ASIC DPRAM auto-increment pointer.
437                                                  */
438                                                 ft1000_write_reg(dev,
439                                                                  FT1000_REG_DPRAM_ADDR,
440                                                                  DWNLD_PS_HDR_LOC);
441
442                                                 for (; word_length > 0; word_length--) {        /* In words */
443                                                         //temp = *pUsFile;
444                                                         //temp = RtlUshortByteSwap(temp);
445                                                         ft1000_write_reg(dev,
446                                                                          FT1000_REG_DPRAM_DATA,
447                                                                          *pUsFile);
448                                                         pUsFile++;
449                                                         pUcFile += 2;
450                                                         DspWordCnt++;
451                                                 }
452                                         } else {
453                                                 /*
454                                                  * Position ASIC DPRAM auto-increment pointer.
455                                                  */
456                                                 outw(DWNLD_MAG_PS_HDR_LOC,
457                                                          dev->base_addr +
458                                                          FT1000_REG_DPRAM_ADDR);
459                                                 if (word_length & 0x01) {
460                                                         word_length++;
461                                                 }
462                                                 word_length = word_length / 2;
463
464                                                 for (; word_length > 0; word_length--) {        /* In words */
465                                                         templong = *pUsFile++;
466                                                         templong |=
467                                                                 (*pUsFile++ << 16);
468                                                         pUcFile += 4;
469                                                         outl(templong,
470                                                                  dev->base_addr +
471                                                                  FT1000_REG_MAG_DPDATAL);
472                                                 }
473                                         }
474                                         spin_unlock_irqrestore(&info->
475                                                                    dpram_lock,
476                                                                    flags);
477                                         break;
478                                 default:
479                                         Status = FAILURE;
480                                         break;
481                                 }
482                                 put_handshake(dev, HANDSHAKE_RESPONSE);
483                         } else {
484                                 Status = FAILURE;
485                         }
486
487                         break;
488
489                 case STATE_CODE_DWNLD:
490                         handshake = get_handshake(dev, HANDSHAKE_REQUEST);
491                         if (handshake == HANDSHAKE_REQUEST) {
492                                 /*
493                                  * Get type associated with the request.
494                                  */
495                                 request = get_request_type(dev);
496                                 switch (request) {
497                                 case REQUEST_FILE_CHECKSUM:
498                                         DEBUG(0,
499                                                   "ft1000_dnld: REQUEST_FOR_CHECKSUM\n");
500                                         put_request_value(dev, image_chksum);
501                                         break;
502                                 case REQUEST_RUN_ADDRESS:
503                                         if (bGoodVersion) {
504                                                 put_request_value(dev,
505                                                                   run_address);
506                                         } else {
507                                                 Status = FAILURE;
508                                                 break;
509                                         }
510                                         break;
511                                 case REQUEST_CODE_LENGTH:
512                                         if (bGoodVersion) {
513                                                 put_request_value(dev,
514                                                                   run_size);
515                                         } else {
516                                                 Status = FAILURE;
517                                                 break;
518                                         }
519                                         break;
520                                 case REQUEST_DONE_CL:
521                                         /* Reposition ptrs to beginning of provisioning section */
522                                         switch (file_version) {
523                                         case 5:
524                                         case 6:
525                                                 pUsFile =
526                                                         (USHORT *) ((long)pFileStart
527                                                                 +
528                                                                 pFileHdr5->
529                                                                 commands_offset);
530                                                 pUcFile =
531                                                         (UCHAR *) ((long)pFileStart
532                                                                    +
533                                                                    pFileHdr5->
534                                                                    commands_offset);
535                                                 break;
536                                         default:
537                                                 Status = FAILURE;
538                                                 break;
539                                         }
540                                         uiState = STATE_DONE_DWNLD;
541                                         break;
542                                 case REQUEST_CODE_SEGMENT:
543                                         if (!bGoodVersion) {
544                                                 Status = FAILURE;
545                                                 break;
546                                         }
547                                         word_length = get_request_value(dev);
548                                         if (word_length > MAX_LENGTH) {
549                                                 Status = FAILURE;
550                                                 break;
551                                         }
552                                         if ((word_length * 2 + (long)pUcFile) >
553                                                 (long)pCodeEnd) {
554                                                 /*
555                                                  * Error, beyond boot code range.
556                                                  */
557                                                 Status = FAILURE;
558                                                 break;
559                                         }
560                                         if (file_version == 5) {
561                                                 /*
562                                                  * Position ASIC DPRAM auto-increment pointer.
563                                                  */
564                                                 ft1000_write_reg(dev,
565                                                                  FT1000_REG_DPRAM_ADDR,
566                                                                  DWNLD_PS_HDR_LOC);
567
568                                                 for (; word_length > 0; word_length--) {        /* In words */
569                                                         //temp = *pUsFile;
570                                                         //temp = RtlUshortByteSwap(temp);
571                                                         ft1000_write_reg(dev,
572                                                                          FT1000_REG_DPRAM_DATA,
573                                                                          *pUsFile);
574                                                         pUsFile++;
575                                                         pUcFile += 2;
576                                                         DspWordCnt++;
577                                                 }
578                                         } else {
579                                                 /*
580                                                  * Position ASIC DPRAM auto-increment pointer.
581                                                  */
582                                                 outw(DWNLD_MAG_PS_HDR_LOC,
583                                                          dev->base_addr +
584                                                          FT1000_REG_DPRAM_ADDR);
585                                                 if (word_length & 0x01) {
586                                                         word_length++;
587                                                 }
588                                                 word_length = word_length / 2;
589
590                                                 for (; word_length > 0; word_length--) {        /* In words */
591                                                         templong = *pUsFile++;
592                                                         templong |=
593                                                                 (*pUsFile++ << 16);
594                                                         pUcFile += 4;
595                                                         outl(templong,
596                                                                  dev->base_addr +
597                                                                  FT1000_REG_MAG_DPDATAL);
598                                                 }
599                                         }
600                                         break;
601
602                                 case REQUEST_MAILBOX_DATA:
603                                         // Convert length from byte count to word count. Make sure we round up.
604                                         word_length =
605                                                 (long)(info->DSPInfoBlklen + 1) / 2;
606                                         put_request_value(dev, word_length);
607                                         pMailBoxData =
608                                                 (PDRVMSG) & info->DSPInfoBlk[0];
609                                         pUsData =
610                                                 (USHORT *) & pMailBoxData->data[0];
611                                         // Provide mutual exclusive access while reading ASIC registers.
612                                         spin_lock_irqsave(&info->dpram_lock,
613                                                           flags);
614                                         if (file_version == 5) {
615                                                 /*
616                                                  * Position ASIC DPRAM auto-increment pointer.
617                                                  */
618                                                 ft1000_write_reg(dev,
619                                                                  FT1000_REG_DPRAM_ADDR,
620                                                                  DWNLD_PS_HDR_LOC);
621
622                                                 for (; word_length > 0; word_length--) {        /* In words */
623                                                         temp = ntohs(*pUsData);
624                                                         ft1000_write_reg(dev,
625                                                                          FT1000_REG_DPRAM_DATA,
626                                                                          temp);
627                                                         pUsData++;
628                                                 }
629                                         } else {
630                                                 /*
631                                                  * Position ASIC DPRAM auto-increment pointer.
632                                                  */
633                                                 outw(DWNLD_MAG_PS_HDR_LOC,
634                                                          dev->base_addr +
635                                                          FT1000_REG_DPRAM_ADDR);
636                                                 if (word_length & 0x01) {
637                                                         word_length++;
638                                                 }
639                                                 word_length = word_length / 2;
640
641                                                 for (; word_length > 0; word_length--) {        /* In words */
642                                                         templong = *pUsData++;
643                                                         templong |=
644                                                                 (*pUsData++ << 16);
645                                                         outl(templong,
646                                                                  dev->base_addr +
647                                                                  FT1000_REG_MAG_DPDATAL);
648                                                 }
649                                         }
650                                         spin_unlock_irqrestore(&info->
651                                                                    dpram_lock,
652                                                                    flags);
653                                         break;
654
655                                 case REQUEST_VERSION_INFO:
656                                         word_length =
657                                                 pFileHdr5->version_data_size;
658                                         put_request_value(dev, word_length);
659                                         pUsFile =
660                                                 (USHORT *) ((long)pFileStart +
661                                                         pFileHdr5->
662                                                         version_data_offset);
663                                         // Provide mutual exclusive access while reading ASIC registers.
664                                         spin_lock_irqsave(&info->dpram_lock,
665                                                           flags);
666                                         if (file_version == 5) {
667                                                 /*
668                                                  * Position ASIC DPRAM auto-increment pointer.
669                                                  */
670                                                 ft1000_write_reg(dev,
671                                                                  FT1000_REG_DPRAM_ADDR,
672                                                                  DWNLD_PS_HDR_LOC);
673
674                                                 for (; word_length > 0; word_length--) {        /* In words */
675                                                         ft1000_write_reg(dev,
676                                                                          FT1000_REG_DPRAM_DATA,
677                                                                          *pUsFile
678                                                                          /*temp */
679                                                                 );
680                                                         pUsFile++;
681                                                 }
682                                         } else {
683                                                 /*
684                                                  * Position ASIC DPRAM auto-increment pointer.
685                                                  */
686                                                 outw(DWNLD_MAG_PS_HDR_LOC,
687                                                          dev->base_addr +
688                                                          FT1000_REG_DPRAM_ADDR);
689                                                 if (word_length & 0x01) {
690                                                         word_length++;
691                                                 }
692                                                 word_length = word_length / 2;
693
694                                                 for (; word_length > 0; word_length--) {        /* In words */
695                                                         templong =
696                                                                 ntohs(*pUsFile++);
697                                                         temp =
698                                                                 ntohs(*pUsFile++);
699                                                         templong |=
700                                                                 (temp << 16);
701                                                         outl(templong,
702                                                                  dev->base_addr +
703                                                                  FT1000_REG_MAG_DPDATAL);
704                                                 }
705                                         }
706                                         spin_unlock_irqrestore(&info->
707                                                                    dpram_lock,
708                                                                    flags);
709                                         break;
710
711                                 case REQUEST_CODE_BY_VERSION:
712                                         bGoodVersion = FALSE;
713                                         requested_version =
714                                                 get_request_value(dev);
715                                         if (file_version == 5) {
716                                                 pDspImageInfo =
717                                                         (PDSP_IMAGE_INFO) ((long)
718                                                                            pFileStart
719                                                                            +
720                                                                            sizeof
721                                                                            (DSP_FILE_HDR_5));
722                                                 for (imageN = 0;
723                                                          imageN <
724                                                          pFileHdr5->nDspImages;
725                                                          imageN++) {
726                                                         if (pDspImageInfo->
727                                                                 version ==
728                                                                 requested_version) {
729                                                                 bGoodVersion =
730                                                                         TRUE;
731                                                                 pUsFile =
732                                                                         (USHORT
733                                                                          *) ((long)
734                                                                          pFileStart
735                                                                          +
736                                                                          pDspImageInfo->
737                                                                          begin_offset);
738                                                                 pUcFile =
739                                                                         (UCHAR
740                                                                          *) ((long)
741                                                                          pFileStart
742                                                                          +
743                                                                          pDspImageInfo->
744                                                                          begin_offset);
745                                                                 pCodeEnd =
746                                                                         (UCHAR
747                                                                          *) ((long)
748                                                                          pFileStart
749                                                                          +
750                                                                          pDspImageInfo->
751                                                                          end_offset);
752                                                                 run_address =
753                                                                         pDspImageInfo->
754                                                                         run_address;
755                                                                 run_size =
756                                                                         pDspImageInfo->
757                                                                         image_size;
758                                                                 break;
759                                                         }
760                                                         pDspImageInfo++;
761                                                 }
762                                         } else {
763                                                 pDspImageInfoV6 =
764                                                         (PDSP_IMAGE_INFO_V6) ((long)
765                                                                           pFileStart
766                                                                           +
767                                                                           sizeof
768                                                                           (DSP_FILE_HDR_5));
769                                                 for (imageN = 0;
770                                                          imageN <
771                                                          pFileHdr5->nDspImages;
772                                                          imageN++) {
773                                                         temp = (USHORT)
774                                                                 (pDspImageInfoV6->
775                                                                  version);
776                                                         templong = temp;
777                                                         temp = (USHORT)
778                                                                 (pDspImageInfoV6->
779                                                                  version >> 16);
780                                                         templong |=
781                                                                 (temp << 16);
782                                                         if (templong ==
783                                                                 requested_version) {
784                                                                 bGoodVersion =
785                                                                         TRUE;
786                                                                 pUsFile =
787                                                                         (USHORT
788                                                                          *) ((long)
789                                                                          pFileStart
790                                                                          +
791                                                                          pDspImageInfoV6->
792                                                                          begin_offset);
793                                                                 pUcFile =
794                                                                         (UCHAR
795                                                                          *) ((long)
796                                                                          pFileStart
797                                                                          +
798                                                                          pDspImageInfoV6->
799                                                                          begin_offset);
800                                                                 pCodeEnd =
801                                                                         (UCHAR
802                                                                          *) ((long)
803                                                                          pFileStart
804                                                                          +
805                                                                          pDspImageInfoV6->
806                                                                          end_offset);
807                                                                 run_address =
808                                                                         pDspImageInfoV6->
809                                                                         run_address;
810                                                                 run_size =
811                                                                         pDspImageInfoV6->
812                                                                         image_size;
813                                                                 image_chksum =
814                                                                         (ULONG)
815                                                                         pDspImageInfoV6->
816                                                                         checksum;
817                                                                 DEBUG(0,
818                                                                           "ft1000_dnld: image_chksum = 0x%8x\n",
819                                                                           (unsigned
820                                                                            int)
821                                                                           image_chksum);
822                                                                 break;
823                                                         }
824                                                         pDspImageInfoV6++;
825                                                 }
826                                         }
827                                         if (!bGoodVersion) {
828                                                 /*
829                                                  * Error, beyond boot code range.
830                                                  */
831                                                 Status = FAILURE;
832                                                 break;
833                                         }
834                                         break;
835
836                                 default:
837                                         Status = FAILURE;
838                                         break;
839                                 }
840                                 put_handshake(dev, HANDSHAKE_RESPONSE);
841                         } else {
842                                 Status = FAILURE;
843                         }
844
845                         break;
846
847                 case STATE_DONE_DWNLD:
848                         if (((unsigned long) (pUcFile) - (unsigned long) pFileStart) >=
849                                 (unsigned long) FileLength) {
850                                 uiState = STATE_DONE_FILE;
851                                 break;
852                         }
853
854                         pHdr = (struct pseudo_hdr *) pUsFile;
855
856                         if (pHdr->portdest == 0x80      /* DspOAM */
857                                 && (pHdr->portsrc == 0x00       /* Driver */
858                                 || pHdr->portsrc == 0x10 /* FMM */ )) {
859                                 uiState = STATE_SECTION_PROV;
860                         } else {
861                                 DEBUG(1,
862                                           "FT1000:download:Download error: Bad Port IDs in Pseudo Record\n");
863                                 DEBUG(1, "\t Port Source = 0x%2.2x\n",
864                                           pHdr->portsrc);
865                                 DEBUG(1, "\t Port Destination = 0x%2.2x\n",
866                                           pHdr->portdest);
867                                 Status = FAILURE;
868                         }
869
870                         break;
871
872                 case STATE_SECTION_PROV:
873
874                         pHdr = (struct pseudo_hdr *) pUcFile;
875
876                         if (pHdr->checksum == hdr_checksum(pHdr)) {
877                                 if (pHdr->portdest != 0x80 /* Dsp OAM */ ) {
878                                         uiState = STATE_DONE_PROV;
879                                         break;
880                                 }
881                                 usHdrLength = ntohs(pHdr->length);      /* Byte length for PROV records */
882
883                                 // Get buffer for provisioning data
884                                 pbuffer =
885                                         kmalloc((usHdrLength + sizeof(struct pseudo_hdr)),
886                                                 GFP_ATOMIC);
887                                 if (pbuffer) {
888                                         memcpy(pbuffer, (void *)pUcFile,
889                                                    (UINT) (usHdrLength +
890                                                            sizeof(struct pseudo_hdr)));
891                                         // link provisioning data
892                                         pprov_record =
893                                                 kmalloc(sizeof(PROV_RECORD),
894                                                         GFP_ATOMIC);
895                                         if (pprov_record) {
896                                                 pprov_record->pprov_data =
897                                                         pbuffer;
898                                                 list_add_tail(&pprov_record->
899                                                                   list,
900                                                                   &info->prov_list);
901                                                 // Move to next entry if available
902                                                 pUcFile =
903                                                         (UCHAR *) ((unsigned long) pUcFile +
904                                                                    (unsigned long) ((usHdrLength + 1) & 0xFFFFFFFE) + sizeof(struct pseudo_hdr));
905                                                 if ((unsigned long) (pUcFile) -
906                                                         (unsigned long) (pFileStart) >=
907                                                         (unsigned long) FileLength) {
908                                                         uiState =
909                                                                 STATE_DONE_FILE;
910                                                 }
911                                         } else {
912                                                 kfree(pbuffer);
913                                                 Status = FAILURE;
914                                         }
915                                 } else {
916                                         Status = FAILURE;
917                                 }
918                         } else {
919                                 /* Checksum did not compute */
920                                 Status = FAILURE;
921                         }
922
923                         break;
924
925                 case STATE_DONE_PROV:
926                         uiState = STATE_DONE_FILE;
927                         break;
928
929                 default:
930                         Status = FAILURE;
931                         break;
932                 }               /* End Switch */
933
934         }                       /* End while */
935
936         return Status;
937
938 }