Commit | Line | Data |
---|---|---|
89a03d36 KN |
1 | /* |
2 | * CopyRight (C) 2007 Qualcomm Inc. All Rights Reserved. | |
3 | * | |
4 | * This file is part of Express Card USB Driver | |
5 | */ | |
f7c1be0c | 6 | |
f7c1be0c MB |
7 | #include <linux/kernel.h> |
8 | #include <linux/module.h> | |
9 | #include <linux/netdevice.h> | |
10 | #include <linux/etherdevice.h> | |
11 | #include <linux/usb.h> | |
12 | #include <linux/vmalloc.h> | |
13 | #include "ft1000_usb.h" | |
14 | ||
f7c1be0c MB |
15 | |
16 | #define DWNLD_HANDSHAKE_LOC 0x02 | |
17 | #define DWNLD_TYPE_LOC 0x04 | |
18 | #define DWNLD_SIZE_MSW_LOC 0x06 | |
19 | #define DWNLD_SIZE_LSW_LOC 0x08 | |
20 | #define DWNLD_PS_HDR_LOC 0x0A | |
21 | ||
22 | #define MAX_DSP_WAIT_LOOPS 40 | |
23 | #define DSP_WAIT_SLEEP_TIME 1000 /* 1 millisecond */ | |
24 | #define DSP_WAIT_DISPATCH_LVL 50 /* 50 usec */ | |
25 | ||
26 | #define HANDSHAKE_TIMEOUT_VALUE 0xF1F1 | |
27 | #define HANDSHAKE_RESET_VALUE 0xFEFE /* When DSP requests startover */ | |
28 | #define HANDSHAKE_RESET_VALUE_USB 0xFE7E /* When DSP requests startover */ | |
29 | #define HANDSHAKE_DSP_BL_READY 0xFEFE /* At start DSP writes this when bootloader ready */ | |
30 | #define HANDSHAKE_DSP_BL_READY_USB 0xFE7E /* At start DSP writes this when bootloader ready */ | |
31 | #define HANDSHAKE_DRIVER_READY 0xFFFF /* Driver writes after receiving 0xFEFE */ | |
32 | #define HANDSHAKE_SEND_DATA 0x0000 /* DSP writes this when ready for more data */ | |
33 | ||
34 | #define HANDSHAKE_REQUEST 0x0001 /* Request from DSP */ | |
35 | #define HANDSHAKE_RESPONSE 0x0000 /* Satisfied DSP request */ | |
36 | ||
37 | #define REQUEST_CODE_LENGTH 0x0000 | |
38 | #define REQUEST_RUN_ADDRESS 0x0001 | |
39 | #define REQUEST_CODE_SEGMENT 0x0002 /* In WORD count */ | |
40 | #define REQUEST_DONE_BL 0x0003 | |
41 | #define REQUEST_DONE_CL 0x0004 | |
42 | #define REQUEST_VERSION_INFO 0x0005 | |
43 | #define REQUEST_CODE_BY_VERSION 0x0006 | |
bf3146c8 | 44 | #define REQUEST_MAILBOX_DATA 0x0007 |
f7c1be0c MB |
45 | #define REQUEST_FILE_CHECKSUM 0x0008 |
46 | ||
47 | #define STATE_START_DWNLD 0x01 | |
48 | #define STATE_BOOT_DWNLD 0x02 | |
49 | #define STATE_CODE_DWNLD 0x03 | |
50 | #define STATE_DONE_DWNLD 0x04 | |
51 | #define STATE_SECTION_PROV 0x05 | |
52 | #define STATE_DONE_PROV 0x06 | |
53 | #define STATE_DONE_FILE 0x07 | |
54 | ||
55 | #define MAX_LENGTH 0x7f0 | |
56 | ||
588c31ea | 57 | /* Temporary download mechanism for Magnemite */ |
f7c1be0c MB |
58 | #define DWNLD_MAG_TYPE_LOC 0x00 |
59 | #define DWNLD_MAG_LEN_LOC 0x01 | |
60 | #define DWNLD_MAG_ADDR_LOC 0x02 | |
61 | #define DWNLD_MAG_CHKSUM_LOC 0x03 | |
62 | #define DWNLD_MAG_VAL_LOC 0x04 | |
63 | ||
64 | #define HANDSHAKE_MAG_DSP_BL_READY 0xFEFE0000 /* At start DSP writes this when bootloader ready */ | |
65 | #define HANDSHAKE_MAG_DSP_ENTRY 0x01000000 /* Dsp writes this to request for entry address */ | |
66 | #define HANDSHAKE_MAG_DSP_DATA 0x02000000 /* Dsp writes this to request for data block */ | |
67 | #define HANDSHAKE_MAG_DSP_DONE 0x03000000 /* Dsp writes this to indicate download done */ | |
68 | ||
bf3146c8 | 69 | #define HANDSHAKE_MAG_DRV_READY 0xFFFF0000 /* Driver writes this to indicate ready to download */ |
f7c1be0c MB |
70 | #define HANDSHAKE_MAG_DRV_DATA 0x02FECDAB /* Driver writes this to indicate data available to DSP */ |
71 | #define HANDSHAKE_MAG_DRV_ENTRY 0x01FECDAB /* Driver writes this to indicate entry point to DSP */ | |
72 | ||
73 | #define HANDSHAKE_MAG_TIMEOUT_VALUE 0xF1F1 | |
74 | ||
75 | ||
588c31ea | 76 | /* New Magnemite downloader */ |
f7c1be0c MB |
77 | #define DWNLD_MAG1_HANDSHAKE_LOC 0x00 |
78 | #define DWNLD_MAG1_TYPE_LOC 0x01 | |
79 | #define DWNLD_MAG1_SIZE_LOC 0x02 | |
80 | #define DWNLD_MAG1_PS_HDR_LOC 0x03 | |
81 | ||
13da8f0d | 82 | struct dsp_file_hdr { |
588c31ea DD |
83 | long version_id; /* Version ID of this image format. */ |
84 | long package_id; /* Package ID of code release. */ | |
85 | long build_date; /* Date/time stamp when file was built. */ | |
86 | long commands_offset; /* Offset to attached commands in Pseudo Hdr format. */ | |
87 | long loader_offset; /* Offset to bootloader code. */ | |
88 | long loader_code_address; /* Start address of bootloader. */ | |
89 | long loader_code_end; /* Where bootloader code ends. */ | |
c4df2822 | 90 | long loader_code_size; |
588c31ea DD |
91 | long version_data_offset; /* Offset were scrambled version data begins. */ |
92 | long version_data_size; /* Size, in words, of scrambled version data. */ | |
93 | long nDspImages; /* Number of DSP images in file. */ | |
13da8f0d | 94 | }; |
f7c1be0c | 95 | |
13da8f0d MB |
96 | #pragma pack(1) |
97 | struct dsp_image_info { | |
588c31ea DD |
98 | long coff_date; /* Date/time when DSP Coff image was built. */ |
99 | long begin_offset; /* Offset in file where image begins. */ | |
100 | long end_offset; /* Offset in file where image begins. */ | |
101 | long run_address; /* On chip Start address of DSP code. */ | |
102 | long image_size; /* Size of image. */ | |
103 | long version; /* Embedded version # of DSP code. */ | |
104 | unsigned short checksum; /* DSP File checksum */ | |
c4df2822 | 105 | unsigned short pad1; |
13da8f0d MB |
106 | }; |
107 | ||
f7c1be0c | 108 | |
de7a0cc1 | 109 | /* checks if the doorbell register is cleared */ |
8cf9ff57 | 110 | static int check_usb_db(struct ft1000_usb *ft1000dev) |
f7c1be0c | 111 | { |
c5d680c0 MB |
112 | int loopcnt; |
113 | u16 temp; | |
8cf9ff57 | 114 | int status; |
c5d680c0 MB |
115 | |
116 | loopcnt = 0; | |
117 | ||
118 | while (loopcnt < 10) { | |
119 | status = ft1000_read_register(ft1000dev, &temp, | |
120 | FT1000_REG_DOORBELL); | |
121 | DEBUG("check_usb_db: read FT1000_REG_DOORBELL value is %x\n", | |
122 | temp); | |
123 | if (temp & 0x0080) { | |
124 | DEBUG("FT1000:Got checkusb doorbell\n"); | |
125 | status = ft1000_write_register(ft1000dev, 0x0080, | |
126 | FT1000_REG_DOORBELL); | |
127 | status = ft1000_write_register(ft1000dev, 0x0100, | |
128 | FT1000_REG_DOORBELL); | |
129 | status = ft1000_write_register(ft1000dev, 0x8000, | |
130 | FT1000_REG_DOORBELL); | |
131 | break; | |
132 | } else { | |
133 | loopcnt++; | |
134 | msleep(10); | |
135 | } | |
136 | ||
137 | } | |
138 | ||
139 | loopcnt = 0; | |
140 | while (loopcnt < 20) { | |
141 | status = ft1000_read_register(ft1000dev, &temp, | |
142 | FT1000_REG_DOORBELL); | |
143 | DEBUG("FT1000:check_usb_db:Doorbell = 0x%x\n", temp); | |
144 | if (temp & 0x8000) { | |
145 | loopcnt++; | |
146 | msleep(10); | |
147 | } else { | |
148 | DEBUG("check_usb_db: door bell is cleared, return 0\n"); | |
149 | return 0; | |
150 | } | |
151 | } | |
152 | ||
547b5b22 | 153 | return -1; |
f7c1be0c MB |
154 | } |
155 | ||
135a9ea0 | 156 | /* gets the handshake and compares it with the expected value */ |
dedbc933 | 157 | static u16 get_handshake(struct ft1000_usb *ft1000dev, u16 expected_value) |
f7c1be0c | 158 | { |
d7a7318b MB |
159 | u16 handshake; |
160 | int loopcnt; | |
8cf9ff57 | 161 | int status = 0; |
f7c1be0c | 162 | |
d7a7318b MB |
163 | loopcnt = 0; |
164 | ||
165 | while (loopcnt < 100) { | |
166 | /* Need to clear downloader doorbell if Hartley ASIC */ | |
167 | status = ft1000_write_register(ft1000dev, FT1000_DB_DNLD_RX, | |
168 | FT1000_REG_DOORBELL); | |
3aa2303a | 169 | if (ft1000dev->fcodeldr) { |
d7a7318b | 170 | DEBUG(" get_handshake: fcodeldr is %d\n", |
3aa2303a OZ |
171 | ft1000dev->fcodeldr); |
172 | ft1000dev->fcodeldr = 0; | |
d7a7318b | 173 | status = check_usb_db(ft1000dev); |
547b5b22 | 174 | if (status != 0) { |
d7a7318b | 175 | DEBUG("get_handshake: check_usb_db failed\n"); |
d7a7318b MB |
176 | break; |
177 | } | |
178 | status = ft1000_write_register(ft1000dev, | |
179 | FT1000_DB_DNLD_RX, | |
180 | FT1000_REG_DOORBELL); | |
181 | } | |
182 | ||
183 | status = ft1000_read_dpram16(ft1000dev, | |
184 | DWNLD_MAG1_HANDSHAKE_LOC, (u8 *)&handshake, 1); | |
185 | handshake = ntohs(handshake); | |
186 | ||
187 | if (status) | |
188 | return HANDSHAKE_TIMEOUT_VALUE; | |
189 | ||
190 | if ((handshake == expected_value) || | |
191 | (handshake == HANDSHAKE_RESET_VALUE_USB)) { | |
192 | return handshake; | |
193 | } else { | |
194 | loopcnt++; | |
195 | msleep(10); | |
196 | } | |
197 | } | |
198 | ||
199 | return HANDSHAKE_TIMEOUT_VALUE; | |
f7c1be0c MB |
200 | } |
201 | ||
fafa4dce | 202 | /* write the handshake value to the handshake location */ |
c4df2822 | 203 | static void put_handshake(struct ft1000_usb *ft1000dev, u16 handshake_value) |
f7c1be0c | 204 | { |
a8d4d198 MB |
205 | u32 tempx; |
206 | u16 tempword; | |
8cf9ff57 | 207 | int status; |
f7c1be0c | 208 | |
a8d4d198 MB |
209 | tempx = (u32)handshake_value; |
210 | tempx = ntohl(tempx); | |
211 | ||
212 | tempword = (u16)(tempx & 0xffff); | |
213 | status = ft1000_write_dpram16(ft1000dev, DWNLD_MAG1_HANDSHAKE_LOC, | |
214 | tempword, 0); | |
215 | tempword = (u16)(tempx >> 16); | |
216 | status = ft1000_write_dpram16(ft1000dev, DWNLD_MAG1_HANDSHAKE_LOC, | |
217 | tempword, 1); | |
218 | status = ft1000_write_register(ft1000dev, FT1000_DB_DNLD_TX, | |
219 | FT1000_REG_DOORBELL); | |
f7c1be0c MB |
220 | } |
221 | ||
dedbc933 | 222 | static u16 get_handshake_usb(struct ft1000_usb *ft1000dev, u16 expected_value) |
f7c1be0c | 223 | { |
5865a18e MB |
224 | u16 handshake; |
225 | int loopcnt; | |
226 | u16 temp; | |
8cf9ff57 | 227 | int status = 0; |
f7c1be0c | 228 | |
5865a18e MB |
229 | loopcnt = 0; |
230 | handshake = 0; | |
231 | ||
232 | while (loopcnt < 100) { | |
3aa2303a | 233 | if (ft1000dev->usbboot == 2) { |
5865a18e | 234 | status = ft1000_read_dpram32(ft1000dev, 0, |
3aa2303a | 235 | (u8 *)&(ft1000dev->tempbuf[0]), 64); |
5865a18e MB |
236 | for (temp = 0; temp < 16; temp++) { |
237 | DEBUG("tempbuf %d = 0x%x\n", temp, | |
3aa2303a | 238 | ft1000dev->tempbuf[temp]); |
5865a18e MB |
239 | } |
240 | status = ft1000_read_dpram16(ft1000dev, | |
241 | DWNLD_MAG1_HANDSHAKE_LOC, | |
242 | (u8 *)&handshake, 1); | |
243 | DEBUG("handshake from read_dpram16 = 0x%x\n", | |
244 | handshake); | |
3aa2303a | 245 | if (ft1000dev->dspalive == ft1000dev->tempbuf[6]) { |
5865a18e MB |
246 | handshake = 0; |
247 | } else { | |
3aa2303a OZ |
248 | handshake = ft1000dev->tempbuf[1]; |
249 | ft1000dev->dspalive = | |
250 | ft1000dev->tempbuf[6]; | |
5865a18e MB |
251 | } |
252 | } else { | |
253 | status = ft1000_read_dpram16(ft1000dev, | |
254 | DWNLD_MAG1_HANDSHAKE_LOC, | |
255 | (u8 *)&handshake, 1); | |
256 | } | |
f7c1be0c | 257 | |
5865a18e MB |
258 | loopcnt++; |
259 | msleep(10); | |
260 | handshake = ntohs(handshake); | |
261 | if ((handshake == expected_value) || | |
262 | (handshake == HANDSHAKE_RESET_VALUE_USB)) | |
263 | return handshake; | |
264 | } | |
265 | ||
266 | return HANDSHAKE_TIMEOUT_VALUE; | |
f7c1be0c MB |
267 | } |
268 | ||
c4df2822 | 269 | static void put_handshake_usb(struct ft1000_usb *ft1000dev, u16 handshake_value) |
f7c1be0c | 270 | { |
5acc5396 | 271 | int i; |
f7c1be0c | 272 | |
c4df2822 AI |
273 | for (i = 0; i < 1000; i++) |
274 | ; | |
f7c1be0c MB |
275 | } |
276 | ||
dedbc933 | 277 | static u16 get_request_type(struct ft1000_usb *ft1000dev) |
f7c1be0c | 278 | { |
9b43f374 | 279 | u16 request_type; |
8cf9ff57 | 280 | int status; |
9b43f374 MB |
281 | u16 tempword; |
282 | u32 tempx; | |
f7c1be0c | 283 | |
3aa2303a | 284 | if (ft1000dev->bootmode == 1) { |
9b43f374 MB |
285 | status = fix_ft1000_read_dpram32(ft1000dev, |
286 | DWNLD_MAG1_TYPE_LOC, (u8 *)&tempx); | |
287 | tempx = ntohl(tempx); | |
288 | } else { | |
289 | tempx = 0; | |
290 | status = ft1000_read_dpram16(ft1000dev, | |
291 | DWNLD_MAG1_TYPE_LOC, (u8 *)&tempword, 1); | |
292 | tempx |= (tempword << 16); | |
293 | tempx = ntohl(tempx); | |
294 | } | |
295 | request_type = (u16)tempx; | |
f7c1be0c | 296 | |
9b43f374 | 297 | return request_type; |
f7c1be0c MB |
298 | } |
299 | ||
dedbc933 | 300 | static u16 get_request_type_usb(struct ft1000_usb *ft1000dev) |
f7c1be0c | 301 | { |
c3ed5d2f | 302 | u16 request_type; |
8cf9ff57 | 303 | int status; |
c3ed5d2f MB |
304 | u16 tempword; |
305 | u32 tempx; | |
f7c1be0c | 306 | |
3aa2303a | 307 | if (ft1000dev->bootmode == 1) { |
c3ed5d2f MB |
308 | status = fix_ft1000_read_dpram32(ft1000dev, |
309 | DWNLD_MAG1_TYPE_LOC, (u8 *)&tempx); | |
310 | tempx = ntohl(tempx); | |
311 | } else { | |
3aa2303a OZ |
312 | if (ft1000dev->usbboot == 2) { |
313 | tempx = ft1000dev->tempbuf[2]; | |
314 | tempword = ft1000dev->tempbuf[3]; | |
c3ed5d2f MB |
315 | } else { |
316 | tempx = 0; | |
317 | status = ft1000_read_dpram16(ft1000dev, | |
318 | DWNLD_MAG1_TYPE_LOC, | |
319 | (u8 *)&tempword, 1); | |
320 | } | |
321 | tempx |= (tempword << 16); | |
322 | tempx = ntohl(tempx); | |
323 | } | |
324 | request_type = (u16)tempx; | |
f7c1be0c | 325 | |
c3ed5d2f | 326 | return request_type; |
f7c1be0c MB |
327 | } |
328 | ||
dedbc933 | 329 | static long get_request_value(struct ft1000_usb *ft1000dev) |
f7c1be0c | 330 | { |
114a06ae MB |
331 | u32 value; |
332 | u16 tempword; | |
8cf9ff57 | 333 | int status; |
f7c1be0c | 334 | |
3aa2303a | 335 | if (ft1000dev->bootmode == 1) { |
114a06ae MB |
336 | status = fix_ft1000_read_dpram32(ft1000dev, |
337 | DWNLD_MAG1_SIZE_LOC, (u8 *)&value); | |
338 | value = ntohl(value); | |
339 | } else { | |
340 | status = ft1000_read_dpram16(ft1000dev, | |
341 | DWNLD_MAG1_SIZE_LOC, (u8 *)&tempword, 0); | |
342 | value = tempword; | |
343 | status = ft1000_read_dpram16(ft1000dev, | |
344 | DWNLD_MAG1_SIZE_LOC, (u8 *)&tempword, 1); | |
345 | value |= (tempword << 16); | |
346 | value = ntohl(value); | |
347 | } | |
f7c1be0c | 348 | |
114a06ae | 349 | return value; |
f7c1be0c MB |
350 | } |
351 | ||
f7c1be0c | 352 | |
9e80d03c | 353 | /* writes a value to DWNLD_MAG1_SIZE_LOC */ |
dedbc933 | 354 | static void put_request_value(struct ft1000_usb *ft1000dev, long lvalue) |
f7c1be0c | 355 | { |
cc4f65bf | 356 | u32 tempx; |
8cf9ff57 | 357 | int status; |
f7c1be0c | 358 | |
cc4f65bf MB |
359 | tempx = ntohl(lvalue); |
360 | status = fix_ft1000_write_dpram32(ft1000dev, DWNLD_MAG1_SIZE_LOC, | |
361 | (u8 *)&tempx); | |
f7c1be0c MB |
362 | } |
363 | ||
364 | ||
365 | ||
b30f4e23 | 366 | /* returns the checksum of the pseudo header */ |
fc549a05 | 367 | static u16 hdr_checksum(struct pseudo_hdr *pHdr) |
f7c1be0c | 368 | { |
78395f67 MB |
369 | u16 *usPtr = (u16 *)pHdr; |
370 | u16 chksum; | |
f7c1be0c | 371 | |
bf3146c8 | 372 | |
78395f67 MB |
373 | chksum = ((((((usPtr[0] ^ usPtr[1]) ^ usPtr[2]) ^ usPtr[3]) ^ |
374 | usPtr[4]) ^ usPtr[5]) ^ usPtr[6]); | |
f7c1be0c | 375 | |
78395f67 | 376 | return chksum; |
f7c1be0c MB |
377 | } |
378 | ||
e7af0786 MB |
379 | static int check_buffers(u16 *buff_w, u16 *buff_r, int len, int offset) |
380 | { | |
381 | int i; | |
382 | ||
383 | for (i = 0; i < len; i++) { | |
384 | if (buff_w[i] != buff_r[i + offset]) | |
43fc69b1 | 385 | return -EREMOTEIO; |
e7af0786 MB |
386 | } |
387 | ||
388 | return 0; | |
389 | } | |
f7c1be0c | 390 | |
eb2ec639 KN |
391 | static int write_dpram32_and_check(struct ft1000_usb *ft1000dev, |
392 | u16 tempbuffer[], u16 dpram) | |
393 | { | |
394 | int status; | |
395 | u16 resultbuffer[64]; | |
396 | int i; | |
397 | ||
398 | for (i = 0; i < 10; i++) { | |
399 | status = ft1000_write_dpram32(ft1000dev, dpram, | |
400 | (u8 *)&tempbuffer[0], 64); | |
43fc69b1 | 401 | if (status == 0) { |
eb2ec639 KN |
402 | /* Work around for ASIC bit stuffing problem. */ |
403 | if ((tempbuffer[31] & 0xfe00) == 0xfe00) { | |
404 | status = ft1000_write_dpram32(ft1000dev, | |
405 | dpram+12, (u8 *)&tempbuffer[24], | |
406 | 64); | |
407 | } | |
408 | /* Let's check the data written */ | |
409 | status = ft1000_read_dpram32(ft1000dev, dpram, | |
410 | (u8 *)&resultbuffer[0], 64); | |
411 | if ((tempbuffer[31] & 0xfe00) == 0xfe00) { | |
412 | if (check_buffers(tempbuffer, resultbuffer, 28, | |
413 | 0)) { | |
414 | DEBUG("FT1000:download:DPRAM write failed 1 during bootloading\n"); | |
415 | usleep_range(9000, 11000); | |
eb2ec639 KN |
416 | break; |
417 | } | |
418 | status = ft1000_read_dpram32(ft1000dev, | |
419 | dpram+12, | |
420 | (u8 *)&resultbuffer[0], 64); | |
421 | ||
422 | if (check_buffers(tempbuffer, resultbuffer, 16, | |
423 | 24)) { | |
424 | DEBUG("FT1000:download:DPRAM write failed 2 during bootloading\n"); | |
425 | usleep_range(9000, 11000); | |
eb2ec639 KN |
426 | break; |
427 | } | |
428 | } else { | |
429 | if (check_buffers(tempbuffer, resultbuffer, 32, | |
430 | 0)) { | |
431 | DEBUG("FT1000:download:DPRAM write failed 3 during bootloading\n"); | |
432 | usleep_range(9000, 11000); | |
eb2ec639 KN |
433 | break; |
434 | } | |
435 | } | |
43fc69b1 | 436 | if (status == 0) |
eb2ec639 KN |
437 | break; |
438 | } | |
439 | } | |
440 | return status; | |
441 | } | |
442 | ||
69f7be1f KN |
443 | /* writes a block of DSP image to DPRAM |
444 | * Parameters: struct ft1000_usb - device structure | |
445 | * u16 **pUsFile - DSP image file pointer in u16 | |
446 | * u8 **pUcFile - DSP image file pointer in u8 | |
447 | * long word_length - length of the buffer to be written to DPRAM | |
448 | */ | |
74827f8d KN |
449 | static int write_blk(struct ft1000_usb *ft1000dev, u16 **pUsFile, u8 **pUcFile, |
450 | long word_length) | |
f7c1be0c | 451 | { |
547b5b22 | 452 | int status = 0; |
74827f8d KN |
453 | u16 dpram; |
454 | int loopcnt, i; | |
455 | u16 tempword; | |
456 | u16 tempbuffer[64]; | |
457 | ||
458 | /*DEBUG("FT1000:download:start word_length = %d\n",(int)word_length); */ | |
459 | dpram = (u16)DWNLD_MAG1_PS_HDR_LOC; | |
460 | tempword = *(*pUsFile); | |
461 | (*pUsFile)++; | |
462 | status = ft1000_write_dpram16(ft1000dev, dpram, tempword, 0); | |
463 | tempword = *(*pUsFile); | |
464 | (*pUsFile)++; | |
465 | status = ft1000_write_dpram16(ft1000dev, dpram++, tempword, 1); | |
466 | ||
467 | *pUcFile = *pUcFile + 4; | |
468 | word_length--; | |
469 | tempword = (u16)word_length; | |
470 | word_length = (word_length / 16) + 1; | |
471 | for (; word_length > 0; word_length--) { /* In words */ | |
472 | loopcnt = 0; | |
473 | for (i = 0; i < 32; i++) { | |
474 | if (tempword != 0) { | |
475 | tempbuffer[i++] = *(*pUsFile); | |
476 | (*pUsFile)++; | |
477 | tempbuffer[i] = *(*pUsFile); | |
478 | (*pUsFile)++; | |
479 | *pUcFile = *pUcFile + 4; | |
480 | loopcnt++; | |
481 | tempword--; | |
482 | } else { | |
483 | tempbuffer[i++] = 0; | |
484 | tempbuffer[i] = 0; | |
485 | } | |
f7c1be0c MB |
486 | } |
487 | ||
74827f8d KN |
488 | /*DEBUG("write_blk: loopcnt is %d\n", loopcnt); */ |
489 | /*DEBUG("write_blk: bootmode = %d\n", bootmode); */ | |
490 | /*DEBUG("write_blk: dpram = %x\n", dpram); */ | |
491 | if (ft1000dev->bootmode == 0) { | |
492 | if (dpram >= 0x3F4) | |
493 | status = ft1000_write_dpram32(ft1000dev, dpram, | |
494 | (u8 *)&tempbuffer[0], 8); | |
495 | else | |
496 | status = ft1000_write_dpram32(ft1000dev, dpram, | |
497 | (u8 *)&tempbuffer[0], 64); | |
498 | } else { | |
499 | status = write_dpram32_and_check(ft1000dev, tempbuffer, | |
500 | dpram); | |
547b5b22 | 501 | if (status != 0) { |
74827f8d KN |
502 | DEBUG("FT1000:download:Write failed tempbuffer[31] = 0x%x\n", tempbuffer[31]); |
503 | break; | |
504 | } | |
505 | } | |
506 | dpram = dpram + loopcnt; | |
507 | } | |
508 | return status; | |
f7c1be0c MB |
509 | } |
510 | ||
c4df2822 | 511 | static void usb_dnld_complete(struct urb *urb) |
f7c1be0c | 512 | { |
588c31ea | 513 | /* DEBUG("****** usb_dnld_complete\n"); */ |
f7c1be0c MB |
514 | } |
515 | ||
456ae7eb KN |
516 | /* writes a block of DSP image to DPRAM |
517 | * Parameters: struct ft1000_usb - device structure | |
518 | * u16 **pUsFile - DSP image file pointer in u16 | |
519 | * u8 **pUcFile - DSP image file pointer in u8 | |
520 | * long word_length - length of the buffer to be written to DPRAM | |
521 | */ | |
8cf9ff57 | 522 | static int write_blk_fifo(struct ft1000_usb *ft1000dev, u16 **pUsFile, |
857af455 | 523 | u8 **pUcFile, long word_length) |
f7c1be0c | 524 | { |
547b5b22 | 525 | int Status = 0; |
857af455 | 526 | int byte_length; |
f7c1be0c | 527 | |
857af455 | 528 | byte_length = word_length * 4; |
f7c1be0c | 529 | |
857af455 MB |
530 | if (byte_length && ((byte_length % 64) == 0)) |
531 | byte_length += 4; | |
f7c1be0c | 532 | |
857af455 MB |
533 | if (byte_length < 64) |
534 | byte_length = 68; | |
f7c1be0c | 535 | |
857af455 MB |
536 | usb_init_urb(ft1000dev->tx_urb); |
537 | memcpy(ft1000dev->tx_buf, *pUcFile, byte_length); | |
538 | usb_fill_bulk_urb(ft1000dev->tx_urb, | |
539 | ft1000dev->dev, | |
540 | usb_sndbulkpipe(ft1000dev->dev, | |
541 | ft1000dev->bulk_out_endpointAddr), | |
542 | ft1000dev->tx_buf, byte_length, usb_dnld_complete, | |
543 | (void *)ft1000dev); | |
bf3146c8 | 544 | |
857af455 | 545 | usb_submit_urb(ft1000dev->tx_urb, GFP_ATOMIC); |
f7c1be0c | 546 | |
857af455 MB |
547 | *pUsFile = *pUsFile + (word_length << 1); |
548 | *pUcFile = *pUcFile + (word_length << 2); | |
f7c1be0c | 549 | |
857af455 | 550 | return Status; |
f7c1be0c MB |
551 | } |
552 | ||
eb3836ce KN |
553 | static int scram_start_dwnld(struct ft1000_usb *ft1000dev, u16 *hshake, |
554 | u32 *state) | |
555 | { | |
b1bdd4d3 | 556 | int status = 0; |
eb3836ce KN |
557 | |
558 | DEBUG("FT1000:STATE_START_DWNLD\n"); | |
559 | if (ft1000dev->usbboot) | |
560 | *hshake = get_handshake_usb(ft1000dev, HANDSHAKE_DSP_BL_READY); | |
561 | else | |
562 | *hshake = get_handshake(ft1000dev, HANDSHAKE_DSP_BL_READY); | |
563 | if (*hshake == HANDSHAKE_DSP_BL_READY) { | |
564 | DEBUG("scram_dnldr: handshake is HANDSHAKE_DSP_BL_READY, call put_handshake(HANDSHAKE_DRIVER_READY)\n"); | |
565 | put_handshake(ft1000dev, HANDSHAKE_DRIVER_READY); | |
b1bdd4d3 KN |
566 | } else if (*hshake == HANDSHAKE_TIMEOUT_VALUE) { |
567 | status = -ETIMEDOUT; | |
eb3836ce KN |
568 | } else { |
569 | DEBUG("FT1000:download:Download error: Handshake failed\n"); | |
b1bdd4d3 | 570 | status = -ENETRESET; |
eb3836ce KN |
571 | } |
572 | *state = STATE_BOOT_DWNLD; | |
573 | return status; | |
574 | } | |
575 | ||
8cf9ff57 | 576 | static int request_code_segment(struct ft1000_usb *ft1000dev, u16 **s_file, |
e0a223b4 | 577 | u8 **c_file, const u8 *endpoint, bool boot_case) |
aaeb94c9 KN |
578 | { |
579 | long word_length; | |
8aced950 | 580 | int status = 0; |
aaeb94c9 KN |
581 | |
582 | /*DEBUG("FT1000:REQUEST_CODE_SEGMENT\n");i*/ | |
583 | word_length = get_request_value(ft1000dev); | |
584 | /*DEBUG("FT1000:word_length = 0x%x\n", (int)word_length); */ | |
585 | /*NdisMSleep (100); */ | |
586 | if (word_length > MAX_LENGTH) { | |
587 | DEBUG("FT1000:download:Download error: Max length exceeded\n"); | |
547b5b22 | 588 | return -1; |
aaeb94c9 | 589 | } |
e0a223b4 | 590 | if ((word_length * 2 + (long)c_file) > (long)endpoint) { |
aaeb94c9 KN |
591 | /* Error, beyond boot code range.*/ |
592 | DEBUG("FT1000:download:Download error: Requested len=%d exceeds BOOT code boundary.\n", (int)word_length); | |
547b5b22 | 593 | return -1; |
aaeb94c9 KN |
594 | } |
595 | if (word_length & 0x1) | |
596 | word_length++; | |
597 | word_length = word_length / 2; | |
aaeb94c9 | 598 | |
e0a223b4 KN |
599 | if (boot_case) { |
600 | status = write_blk(ft1000dev, s_file, c_file, word_length); | |
601 | /*DEBUG("write_blk returned %d\n", status); */ | |
602 | } else { | |
8a76714d | 603 | status = write_blk_fifo(ft1000dev, s_file, c_file, word_length); |
e0a223b4 KN |
604 | if (ft1000dev->usbboot == 0) |
605 | ft1000dev->usbboot++; | |
606 | if (ft1000dev->usbboot == 1) | |
8a76714d | 607 | status |= ft1000_write_dpram16(ft1000dev, |
e0a223b4 KN |
608 | DWNLD_MAG1_PS_HDR_LOC, 0, 0); |
609 | } | |
aaeb94c9 KN |
610 | return status; |
611 | } | |
612 | ||
4b31e1f8 | 613 | /* Scramble downloader for Harley based ASIC via USB interface */ |
8cf9ff57 | 614 | int scram_dnldr(struct ft1000_usb *ft1000dev, void *pFileStart, |
6f953fbb | 615 | u32 FileLength) |
f7c1be0c | 616 | { |
547b5b22 | 617 | int status = 0; |
6f953fbb MB |
618 | u32 state; |
619 | u16 handshake; | |
0ce72ea3 | 620 | struct pseudo_hdr *pseudo_header; |
6f953fbb MB |
621 | u16 pseudo_header_len; |
622 | long word_length; | |
623 | u16 request; | |
624 | u16 temp; | |
f7c1be0c | 625 | |
0ce72ea3 MB |
626 | struct dsp_file_hdr *file_hdr; |
627 | struct dsp_image_info *dsp_img_info = NULL; | |
6f953fbb MB |
628 | long requested_version; |
629 | bool correct_version; | |
0ce72ea3 | 630 | struct drv_msg *mailbox_data; |
6f953fbb MB |
631 | u16 *data = NULL; |
632 | u16 *s_file = NULL; | |
633 | u8 *c_file = NULL; | |
634 | u8 *boot_end = NULL, *code_end = NULL; | |
635 | int image; | |
636 | long loader_code_address, loader_code_size = 0; | |
637 | long run_address = 0, run_size = 0; | |
638 | ||
639 | u32 templong; | |
640 | u32 image_chksum = 0; | |
641 | ||
642 | u16 dpram = 0; | |
643 | u8 *pbuffer; | |
e27d96dd | 644 | struct prov_record *pprov_record; |
1a88a068 | 645 | struct ft1000_info *pft1000info = netdev_priv(ft1000dev->net); |
bf3146c8 | 646 | |
6f953fbb MB |
647 | DEBUG("Entered scram_dnldr...\n"); |
648 | ||
3aa2303a OZ |
649 | ft1000dev->fcodeldr = 0; |
650 | ft1000dev->usbboot = 0; | |
651 | ft1000dev->dspalive = 0xffff; | |
f7c1be0c | 652 | |
588c31ea DD |
653 | /* |
654 | * Get version id of file, at first 4 bytes of file, for newer files. | |
655 | */ | |
f7c1be0c | 656 | |
6f953fbb | 657 | state = STATE_START_DWNLD; |
f7c1be0c | 658 | |
6f953fbb | 659 | file_hdr = (struct dsp_file_hdr *)pFileStart; |
f7c1be0c | 660 | |
6f953fbb | 661 | ft1000_write_register(ft1000dev, 0x800, FT1000_REG_MAG_WATERMARK); |
f7c1be0c | 662 | |
6f953fbb MB |
663 | s_file = (u16 *) (pFileStart + file_hdr->loader_offset); |
664 | c_file = (u8 *) (pFileStart + file_hdr->loader_offset); | |
f7c1be0c | 665 | |
6f953fbb | 666 | boot_end = (u8 *) (pFileStart + file_hdr->loader_code_end); |
f7c1be0c | 667 | |
6f953fbb MB |
668 | loader_code_address = file_hdr->loader_code_address; |
669 | loader_code_size = file_hdr->loader_code_size; | |
36f955bf | 670 | correct_version = false; |
6f953fbb | 671 | |
547b5b22 | 672 | while ((status == 0) && (state != STATE_DONE_FILE)) { |
6f953fbb MB |
673 | switch (state) { |
674 | case STATE_START_DWNLD: | |
eb3836ce KN |
675 | status = scram_start_dwnld(ft1000dev, &handshake, |
676 | &state); | |
6f953fbb | 677 | break; |
f7c1be0c | 678 | |
6f953fbb MB |
679 | case STATE_BOOT_DWNLD: |
680 | DEBUG("FT1000:STATE_BOOT_DWNLD\n"); | |
3aa2303a | 681 | ft1000dev->bootmode = 1; |
6f953fbb MB |
682 | handshake = get_handshake(ft1000dev, HANDSHAKE_REQUEST); |
683 | if (handshake == HANDSHAKE_REQUEST) { | |
684 | /* | |
685 | * Get type associated with the request. | |
686 | */ | |
687 | request = get_request_type(ft1000dev); | |
688 | switch (request) { | |
689 | case REQUEST_RUN_ADDRESS: | |
690 | DEBUG("FT1000:REQUEST_RUN_ADDRESS\n"); | |
691 | put_request_value(ft1000dev, | |
692 | loader_code_address); | |
693 | break; | |
694 | case REQUEST_CODE_LENGTH: | |
695 | DEBUG("FT1000:REQUEST_CODE_LENGTH\n"); | |
696 | put_request_value(ft1000dev, | |
697 | loader_code_size); | |
698 | break; | |
699 | case REQUEST_DONE_BL: | |
700 | DEBUG("FT1000:REQUEST_DONE_BL\n"); | |
701 | /* Reposition ptrs to beginning of code section */ | |
702 | s_file = (u16 *) (boot_end); | |
703 | c_file = (u8 *) (boot_end); | |
588c31ea DD |
704 | /* DEBUG("FT1000:download:s_file = 0x%8x\n", (int)s_file); */ |
705 | /* DEBUG("FT1000:download:c_file = 0x%8x\n", (int)c_file); */ | |
6f953fbb | 706 | state = STATE_CODE_DWNLD; |
3aa2303a | 707 | ft1000dev->fcodeldr = 1; |
6f953fbb MB |
708 | break; |
709 | case REQUEST_CODE_SEGMENT: | |
aaeb94c9 KN |
710 | status = request_code_segment(ft1000dev, |
711 | &s_file, &c_file, | |
e0a223b4 KN |
712 | (const u8 *)boot_end, |
713 | true); | |
aaeb94c9 | 714 | break; |
6f953fbb MB |
715 | default: |
716 | DEBUG | |
717 | ("FT1000:download:Download error: Bad request type=%d in BOOT download state.\n", | |
718 | request); | |
547b5b22 | 719 | status = -1; |
6f953fbb MB |
720 | break; |
721 | } | |
3aa2303a | 722 | if (ft1000dev->usbboot) |
6f953fbb MB |
723 | put_handshake_usb(ft1000dev, |
724 | HANDSHAKE_RESPONSE); | |
725 | else | |
726 | put_handshake(ft1000dev, | |
727 | HANDSHAKE_RESPONSE); | |
728 | } else { | |
729 | DEBUG | |
730 | ("FT1000:download:Download error: Handshake failed\n"); | |
547b5b22 | 731 | status = -1; |
6f953fbb MB |
732 | } |
733 | ||
734 | break; | |
735 | ||
736 | case STATE_CODE_DWNLD: | |
588c31ea | 737 | /* DEBUG("FT1000:STATE_CODE_DWNLD\n"); */ |
3aa2303a OZ |
738 | ft1000dev->bootmode = 0; |
739 | if (ft1000dev->usbboot) | |
6f953fbb MB |
740 | handshake = |
741 | get_handshake_usb(ft1000dev, | |
742 | HANDSHAKE_REQUEST); | |
743 | else | |
744 | handshake = | |
745 | get_handshake(ft1000dev, HANDSHAKE_REQUEST); | |
746 | if (handshake == HANDSHAKE_REQUEST) { | |
747 | /* | |
748 | * Get type associated with the request. | |
749 | */ | |
3aa2303a | 750 | if (ft1000dev->usbboot) |
6f953fbb MB |
751 | request = |
752 | get_request_type_usb(ft1000dev); | |
753 | else | |
754 | request = get_request_type(ft1000dev); | |
755 | switch (request) { | |
756 | case REQUEST_FILE_CHECKSUM: | |
757 | DEBUG | |
758 | ("FT1000:download:image_chksum = 0x%8x\n", | |
759 | image_chksum); | |
760 | put_request_value(ft1000dev, | |
761 | image_chksum); | |
762 | break; | |
763 | case REQUEST_RUN_ADDRESS: | |
764 | DEBUG | |
765 | ("FT1000:download: REQUEST_RUN_ADDRESS\n"); | |
766 | if (correct_version) { | |
767 | DEBUG | |
768 | ("FT1000:download:run_address = 0x%8x\n", | |
769 | (int)run_address); | |
770 | put_request_value(ft1000dev, | |
771 | run_address); | |
772 | } else { | |
773 | DEBUG | |
774 | ("FT1000:download:Download error: Got Run address request before image offset request.\n"); | |
547b5b22 | 775 | status = -1; |
6f953fbb MB |
776 | break; |
777 | } | |
778 | break; | |
779 | case REQUEST_CODE_LENGTH: | |
780 | DEBUG | |
781 | ("FT1000:download:REQUEST_CODE_LENGTH\n"); | |
782 | if (correct_version) { | |
783 | DEBUG | |
784 | ("FT1000:download:run_size = 0x%8x\n", | |
785 | (int)run_size); | |
786 | put_request_value(ft1000dev, | |
787 | run_size); | |
788 | } else { | |
789 | DEBUG | |
790 | ("FT1000:download:Download error: Got Size request before image offset request.\n"); | |
547b5b22 | 791 | status = -1; |
6f953fbb MB |
792 | break; |
793 | } | |
794 | break; | |
795 | case REQUEST_DONE_CL: | |
3aa2303a | 796 | ft1000dev->usbboot = 3; |
6f953fbb MB |
797 | /* Reposition ptrs to beginning of provisioning section */ |
798 | s_file = | |
799 | (u16 *) (pFileStart + | |
800 | file_hdr->commands_offset); | |
801 | c_file = | |
802 | (u8 *) (pFileStart + | |
803 | file_hdr->commands_offset); | |
804 | state = STATE_DONE_DWNLD; | |
805 | break; | |
806 | case REQUEST_CODE_SEGMENT: | |
588c31ea | 807 | /* DEBUG("FT1000:download: REQUEST_CODE_SEGMENT - CODELOADER\n"); */ |
6f953fbb MB |
808 | if (!correct_version) { |
809 | DEBUG | |
810 | ("FT1000:download:Download error: Got Code Segment request before image offset request.\n"); | |
547b5b22 | 811 | status = -1; |
6f953fbb MB |
812 | break; |
813 | } | |
814 | ||
e0a223b4 KN |
815 | status = request_code_segment(ft1000dev, |
816 | &s_file, &c_file, | |
817 | (const u8 *)code_end, | |
818 | false); | |
6f953fbb MB |
819 | |
820 | break; | |
821 | ||
822 | case REQUEST_MAILBOX_DATA: | |
823 | DEBUG | |
824 | ("FT1000:download: REQUEST_MAILBOX_DATA\n"); | |
588c31ea | 825 | /* Convert length from byte count to word count. Make sure we round up. */ |
6f953fbb MB |
826 | word_length = |
827 | (long)(pft1000info->DSPInfoBlklen + | |
828 | 1) / 2; | |
829 | put_request_value(ft1000dev, | |
830 | word_length); | |
831 | mailbox_data = | |
832 | (struct drv_msg *)&(pft1000info-> | |
833 | DSPInfoBlk[0]); | |
834 | /* | |
835 | * Position ASIC DPRAM auto-increment pointer. | |
836 | */ | |
837 | ||
c4df2822 | 838 | data = (u16 *) &mailbox_data->data[0]; |
6f953fbb MB |
839 | dpram = (u16) DWNLD_MAG1_PS_HDR_LOC; |
840 | if (word_length & 0x1) | |
841 | word_length++; | |
842 | ||
843 | word_length = (word_length / 2); | |
844 | ||
845 | for (; word_length > 0; word_length--) { /* In words */ | |
846 | ||
847 | templong = *data++; | |
848 | templong |= (*data++ << 16); | |
849 | status = | |
850 | fix_ft1000_write_dpram32 | |
851 | (ft1000dev, dpram++, | |
c4df2822 | 852 | (u8 *) &templong); |
6f953fbb MB |
853 | |
854 | } | |
855 | break; | |
856 | ||
857 | case REQUEST_VERSION_INFO: | |
858 | DEBUG | |
859 | ("FT1000:download:REQUEST_VERSION_INFO\n"); | |
860 | word_length = | |
861 | file_hdr->version_data_size; | |
862 | put_request_value(ft1000dev, | |
863 | word_length); | |
864 | /* | |
865 | * Position ASIC DPRAM auto-increment pointer. | |
866 | */ | |
867 | ||
868 | s_file = | |
869 | (u16 *) (pFileStart + | |
870 | file_hdr-> | |
871 | version_data_offset); | |
872 | ||
873 | dpram = (u16) DWNLD_MAG1_PS_HDR_LOC; | |
874 | if (word_length & 0x1) | |
875 | word_length++; | |
876 | ||
877 | word_length = (word_length / 2); | |
878 | ||
879 | for (; word_length > 0; word_length--) { /* In words */ | |
880 | ||
881 | templong = ntohs(*s_file++); | |
882 | temp = ntohs(*s_file++); | |
883 | templong |= (temp << 16); | |
884 | status = | |
885 | fix_ft1000_write_dpram32 | |
886 | (ft1000dev, dpram++, | |
610554d3 | 887 | (u8 *) &templong); |
6f953fbb MB |
888 | |
889 | } | |
890 | break; | |
891 | ||
892 | case REQUEST_CODE_BY_VERSION: | |
893 | DEBUG | |
894 | ("FT1000:download:REQUEST_CODE_BY_VERSION\n"); | |
36f955bf | 895 | correct_version = false; |
6f953fbb MB |
896 | requested_version = |
897 | get_request_value(ft1000dev); | |
898 | ||
899 | dsp_img_info = | |
900 | (struct dsp_image_info *)(pFileStart | |
901 | + | |
902 | sizeof | |
903 | (struct | |
904 | dsp_file_hdr)); | |
905 | ||
906 | for (image = 0; | |
907 | image < file_hdr->nDspImages; | |
908 | image++) { | |
909 | ||
dfc9539f MB |
910 | if (dsp_img_info->version == |
911 | requested_version) { | |
36f955bf | 912 | correct_version = true; |
6f953fbb MB |
913 | DEBUG |
914 | ("FT1000:download: correct_version is TRUE\n"); | |
915 | s_file = | |
916 | (u16 *) (pFileStart | |
917 | + | |
918 | dsp_img_info-> | |
919 | begin_offset); | |
920 | c_file = | |
921 | (u8 *) (pFileStart + | |
922 | dsp_img_info-> | |
923 | begin_offset); | |
924 | code_end = | |
925 | (u8 *) (pFileStart + | |
926 | dsp_img_info-> | |
927 | end_offset); | |
928 | run_address = | |
929 | dsp_img_info-> | |
930 | run_address; | |
931 | run_size = | |
932 | dsp_img_info-> | |
933 | image_size; | |
934 | image_chksum = | |
935 | (u32) dsp_img_info-> | |
936 | checksum; | |
937 | break; | |
938 | } | |
939 | dsp_img_info++; | |
940 | ||
588c31ea | 941 | } /* end of for */ |
6f953fbb MB |
942 | |
943 | if (!correct_version) { | |
944 | /* | |
945 | * Error, beyond boot code range. | |
946 | */ | |
947 | DEBUG | |
948 | ("FT1000:download:Download error: Bad Version Request = 0x%x.\n", | |
949 | (int)requested_version); | |
547b5b22 | 950 | status = -1; |
6f953fbb MB |
951 | break; |
952 | } | |
953 | break; | |
954 | ||
955 | default: | |
956 | DEBUG | |
957 | ("FT1000:download:Download error: Bad request type=%d in CODE download state.\n", | |
958 | request); | |
547b5b22 | 959 | status = -1; |
6f953fbb MB |
960 | break; |
961 | } | |
3aa2303a | 962 | if (ft1000dev->usbboot) |
6f953fbb MB |
963 | put_handshake_usb(ft1000dev, |
964 | HANDSHAKE_RESPONSE); | |
965 | else | |
966 | put_handshake(ft1000dev, | |
967 | HANDSHAKE_RESPONSE); | |
968 | } else { | |
969 | DEBUG | |
970 | ("FT1000:download:Download error: Handshake failed\n"); | |
547b5b22 | 971 | status = -1; |
6f953fbb MB |
972 | } |
973 | ||
974 | break; | |
975 | ||
976 | case STATE_DONE_DWNLD: | |
977 | DEBUG("FT1000:download:Code loader is done...\n"); | |
978 | state = STATE_SECTION_PROV; | |
979 | break; | |
980 | ||
981 | case STATE_SECTION_PROV: | |
982 | DEBUG("FT1000:download:STATE_SECTION_PROV\n"); | |
983 | pseudo_header = (struct pseudo_hdr *)c_file; | |
984 | ||
985 | if (pseudo_header->checksum == | |
986 | hdr_checksum(pseudo_header)) { | |
987 | if (pseudo_header->portdest != | |
6f5519fd | 988 | 0x80 /* Dsp OAM */) { |
6f953fbb MB |
989 | state = STATE_DONE_PROV; |
990 | break; | |
991 | } | |
992 | pseudo_header_len = ntohs(pseudo_header->length); /* Byte length for PROV records */ | |
993 | ||
0c5e802c | 994 | /* Get buffer for provisioning data */ |
6f953fbb MB |
995 | pbuffer = |
996 | kmalloc((pseudo_header_len + | |
997 | sizeof(struct pseudo_hdr)), | |
998 | GFP_ATOMIC); | |
999 | if (pbuffer) { | |
1000 | memcpy(pbuffer, (void *)c_file, | |
1001 | (u32) (pseudo_header_len + | |
1002 | sizeof(struct | |
1003 | pseudo_hdr))); | |
588c31ea | 1004 | /* link provisioning data */ |
6f953fbb MB |
1005 | pprov_record = |
1006 | kmalloc(sizeof(struct prov_record), | |
1007 | GFP_ATOMIC); | |
1008 | if (pprov_record) { | |
1009 | pprov_record->pprov_data = | |
1010 | pbuffer; | |
1011 | list_add_tail(&pprov_record-> | |
1012 | list, | |
1013 | &pft1000info-> | |
1014 | prov_list); | |
588c31ea | 1015 | /* Move to next entry if available */ |
6f953fbb MB |
1016 | c_file = |
1017 | (u8 *) ((unsigned long) | |
1018 | c_file + | |
1019 | (u32) ((pseudo_header_len + 1) & 0xFFFFFFFE) + sizeof(struct pseudo_hdr)); | |
1020 | if ((unsigned long)(c_file) - | |
1021 | (unsigned long)(pFileStart) | |
1022 | >= | |
1023 | (unsigned long)FileLength) { | |
1024 | state = STATE_DONE_FILE; | |
1025 | } | |
1026 | } else { | |
1027 | kfree(pbuffer); | |
547b5b22 | 1028 | status = -1; |
6f953fbb MB |
1029 | } |
1030 | } else { | |
547b5b22 | 1031 | status = -1; |
6f953fbb MB |
1032 | } |
1033 | } else { | |
1034 | /* Checksum did not compute */ | |
547b5b22 | 1035 | status = -1; |
6f953fbb MB |
1036 | } |
1037 | DEBUG | |
1038 | ("ft1000:download: after STATE_SECTION_PROV, state = %d, status= %d\n", | |
1039 | state, status); | |
1040 | break; | |
1041 | ||
1042 | case STATE_DONE_PROV: | |
1043 | DEBUG("FT1000:download:STATE_DONE_PROV\n"); | |
1044 | state = STATE_DONE_FILE; | |
1045 | break; | |
1046 | ||
1047 | default: | |
547b5b22 | 1048 | status = -1; |
6f953fbb MB |
1049 | break; |
1050 | } /* End Switch */ | |
1051 | ||
547b5b22 | 1052 | if (status != 0) |
6f953fbb | 1053 | break; |
f7c1be0c MB |
1054 | |
1055 | /**** | |
1056 | // Check if Card is present | |
0ce72ea3 MB |
1057 | status = Harley_Read_Register(&temp, FT1000_REG_SUP_IMASK); |
1058 | if ( (status != NDIS_STATUS_SUCCESS) || (temp == 0x0000) ) { | |
c4df2822 | 1059 | break; |
f7c1be0c MB |
1060 | } |
1061 | ||
0ce72ea3 MB |
1062 | status = Harley_Read_Register(&temp, FT1000_REG_ASIC_ID); |
1063 | if ( (status != NDIS_STATUS_SUCCESS) || (temp == 0xffff) ) { | |
c4df2822 | 1064 | break; |
f7c1be0c MB |
1065 | } |
1066 | ****/ | |
1067 | ||
6f953fbb | 1068 | } /* End while */ |
bf3146c8 | 1069 | |
6f953fbb MB |
1070 | DEBUG("Download exiting with status = 0x%8x\n", status); |
1071 | ft1000_write_register(ft1000dev, FT1000_DB_DNLD_TX, | |
1072 | FT1000_REG_DOORBELL); | |
f7c1be0c | 1073 | |
6f953fbb | 1074 | return status; |
f7c1be0c | 1075 | } |