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