Merge scsi2sd-util GUI changes
[SCSI2SD.git] / software / SCSI2SD / src / sd.c
1 //      Copyright (C) 2013 Michael McMaster <michael@codesrc.com>\r
2 //\r
3 //      This file is part of SCSI2SD.\r
4 //\r
5 //      SCSI2SD is free software: you can redistribute it and/or modify\r
6 //      it under the terms of the GNU General Public License as published by\r
7 //      the Free Software Foundation, either version 3 of the License, or\r
8 //      (at your option) any later version.\r
9 //\r
10 //      SCSI2SD is distributed in the hope that it will be useful,\r
11 //      but WITHOUT ANY WARRANTY; without even the implied warranty of\r
12 //      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
13 //      GNU General Public License for more details.\r
14 //\r
15 //      You should have received a copy of the GNU General Public License\r
16 //      along with SCSI2SD.  If not, see <http://www.gnu.org/licenses/>.\r
17 \r
18 #include "device.h"\r
19 #include "scsi.h"\r
20 #include "config.h"\r
21 #include "disk.h"\r
22 #include "sd.h"\r
23 #include "led.h"\r
24 #include "time.h"\r
25 \r
26 #include "scsiPhy.h"\r
27 \r
28 #include <string.h>\r
29 \r
30 // Global\r
31 SdDevice sdDev;\r
32 \r
33 // Private DMA variables.\r
34 static int dmaInProgress = 0;\r
35 static uint8 sdDMARxChan = CY_DMA_INVALID_CHANNEL;\r
36 static uint8 sdDMATxChan = CY_DMA_INVALID_CHANNEL;\r
37 \r
38 // DMA descriptors\r
39 static uint8 sdDMARxTd[2] = { CY_DMA_INVALID_TD, CY_DMA_INVALID_TD };\r
40 static uint8 sdDMATxTd[2] = { CY_DMA_INVALID_TD, CY_DMA_INVALID_TD };\r
41 \r
42 // Dummy location for DMA to send unchecked CRC bytes to\r
43 static uint8 discardBuffer;\r
44 \r
45 // Source of dummy SPI bytes for DMA\r
46 static uint8 dummyBuffer = 0xFF;\r
47 \r
48 volatile static uint8 rxDMAComplete;\r
49 volatile static uint8 txDMAComplete;\r
50 \r
51 CY_ISR_PROTO(sdRxISR);\r
52 CY_ISR(sdRxISR)\r
53 {\r
54         rxDMAComplete = 1;\r
55 }\r
56 CY_ISR_PROTO(sdTxISR);\r
57 CY_ISR(sdTxISR)\r
58 {\r
59         txDMAComplete = 1;\r
60 }\r
61 \r
62 static uint8 sdCrc7(uint8* chr, uint8 cnt, uint8 crc)\r
63 {\r
64         uint8 a;\r
65         for(a = 0; a < cnt; a++)\r
66         {\r
67                 uint8 Data = chr[a];\r
68                 uint8 i;\r
69                 for(i = 0; i < 8; i++)\r
70                 {\r
71                         crc <<= 1;\r
72                         if( (Data & 0x80) ^ (crc & 0x80) ) {crc ^= 0x09;}\r
73                         Data <<= 1;\r
74                 }\r
75         }\r
76         return crc & 0x7F;\r
77 }\r
78 \r
79 // Read and write 1 byte.\r
80 static uint8 sdSpiByte(uint8 value)\r
81 {\r
82         SDCard_WriteTxData(value);\r
83         while (!(SDCard_ReadRxStatus() & SDCard_STS_RX_FIFO_NOT_EMPTY)) {}\r
84         return SDCard_ReadRxData();\r
85 }\r
86 \r
87 static void sdSendCRCCommand(uint8 cmd, uint32 param)\r
88 {\r
89         uint8 send[6];\r
90 \r
91         send[0] = cmd | 0x40;\r
92         send[1] = param >> 24;\r
93         send[2] = param >> 16;\r
94         send[3] = param >> 8;\r
95         send[4] = param;\r
96         send[5] = (sdCrc7(send, 5, 0) << 1) | 1;\r
97 \r
98         for(cmd = 0; cmd < sizeof(send); cmd++)\r
99         {\r
100                 sdSpiByte(send[cmd]);\r
101         }\r
102         // Allow command to process before reading result code.\r
103         sdSpiByte(0xFF);\r
104 }\r
105 \r
106 static void sdSendCommand(uint8 cmd, uint32 param)\r
107 {\r
108         uint8 send[6];\r
109 \r
110         send[0] = cmd | 0x40;\r
111         send[1] = param >> 24;\r
112         send[2] = param >> 16;\r
113         send[3] = param >> 8;\r
114         send[4] = param;\r
115         send[5] = 1; // 7:1 CRC, 0: Stop bit.\r
116 \r
117         for(cmd = 0; cmd < sizeof(send); cmd++)\r
118         {\r
119                 sdSpiByte(send[cmd]);\r
120         }\r
121         // Allow command to process before reading result code.\r
122         sdSpiByte(0xFF);\r
123 }\r
124 \r
125 static uint8 sdReadResp()\r
126 {\r
127         uint8 v;\r
128         uint8 i = 128;\r
129         do\r
130         {\r
131                 v = sdSpiByte(0xFF);\r
132         } while(i-- && (v & 0x80));\r
133         return v;\r
134 }\r
135 \r
136 static uint8 sdCommandAndResponse(uint8 cmd, uint32 param)\r
137 {\r
138         sdSpiByte(0xFF);\r
139         sdSendCommand(cmd, param);\r
140         return sdReadResp();\r
141 }\r
142 \r
143 static uint8 sdCRCCommandAndResponse(uint8 cmd, uint32 param)\r
144 {\r
145         sdSpiByte(0xFF);\r
146         sdSendCRCCommand(cmd, param);\r
147         return sdReadResp();\r
148 }\r
149 \r
150 // Clear the sticky status bits on error.\r
151 static void sdClearStatus()\r
152 {\r
153         uint8 r2hi = sdCRCCommandAndResponse(SD_SEND_STATUS, 0);\r
154         uint8 r2lo = sdSpiByte(0xFF);\r
155         (void) r2hi; (void) r2lo;\r
156 }\r
157 \r
158 \r
159 void\r
160 sdReadMultiSectorPrep()\r
161 {\r
162         uint8 v;\r
163         uint32 scsiLBA = (transfer.lba + transfer.currentBlock);\r
164         uint32 sdLBA = SCSISector2SD(scsiLBA);\r
165 \r
166         if (!sdDev.ccs)\r
167         {\r
168                 sdLBA = sdLBA * SD_SECTOR_SIZE;\r
169         }\r
170         v = sdCommandAndResponse(SD_READ_MULTIPLE_BLOCK, sdLBA);\r
171         if (v)\r
172         {\r
173                 scsiDiskReset();\r
174                 sdClearStatus();\r
175 \r
176                 scsiDev.status = CHECK_CONDITION;\r
177                 scsiDev.sense.code = HARDWARE_ERROR;\r
178                 scsiDev.sense.asc = LOGICAL_UNIT_COMMUNICATION_FAILURE;\r
179                 scsiDev.phase = STATUS;\r
180         }\r
181         else\r
182         {\r
183                 transfer.inProgress = 1;\r
184         }\r
185 }\r
186 \r
187 static void\r
188 dmaReadSector(uint8_t* outputBuffer)\r
189 {\r
190         // Wait for a start-block token.\r
191         // Don't wait more than 200ms.\r
192         // The standard recommends 100ms.\r
193         uint32_t start = getTime_ms();\r
194         uint8 token = sdSpiByte(0xFF);\r
195         while (token != 0xFE && (diffTime_ms(start, getTime_ms()) <= 200))\r
196         {\r
197                 token = sdSpiByte(0xFF);\r
198         }\r
199         if (token != 0xFE)\r
200         {\r
201                 if (transfer.multiBlock)\r
202                 {\r
203                         sdCompleteRead();\r
204                 }\r
205                 if (scsiDev.status != CHECK_CONDITION)\r
206                 {\r
207                         scsiDev.status = CHECK_CONDITION;\r
208                         scsiDev.sense.code = HARDWARE_ERROR;\r
209                         scsiDev.sense.asc = UNRECOVERED_READ_ERROR;\r
210                         scsiDev.phase = STATUS;\r
211                 }\r
212                 return;\r
213         }\r
214 \r
215         // Receive 512 bytes of data and then 2 bytes CRC.\r
216         CyDmaTdSetConfiguration(sdDMARxTd[0], SD_SECTOR_SIZE, sdDMARxTd[1], TD_INC_DST_ADR);\r
217         CyDmaTdSetAddress(sdDMARxTd[0], LO16((uint32)SDCard_RXDATA_PTR), LO16((uint32)outputBuffer));\r
218         CyDmaTdSetConfiguration(sdDMARxTd[1], 2, CY_DMA_DISABLE_TD, SD_RX_DMA__TD_TERMOUT_EN);\r
219         CyDmaTdSetAddress(sdDMARxTd[1], LO16((uint32)SDCard_RXDATA_PTR), LO16((uint32)&discardBuffer));\r
220 \r
221         CyDmaTdSetConfiguration(sdDMATxTd[0], SD_SECTOR_SIZE + 2, CY_DMA_DISABLE_TD, SD_TX_DMA__TD_TERMOUT_EN);\r
222         CyDmaTdSetAddress(sdDMATxTd[0], LO16((uint32)&dummyBuffer), LO16((uint32)SDCard_TXDATA_PTR));\r
223 \r
224         dmaInProgress = 1;\r
225         // The DMA controller is a bit trigger-happy. It will retain\r
226         // a drq request that was triggered while the channel was\r
227         // disabled.\r
228         CyDmaClearPendingDrq(sdDMATxChan);\r
229         CyDmaClearPendingDrq(sdDMARxChan);\r
230 \r
231         txDMAComplete = 0;\r
232         rxDMAComplete = 0;\r
233 \r
234         // Re-loading the initial TD's here is very important, or else\r
235         // we'll be re-using the last-used TD, which would be the last\r
236         // in the chain (ie. CRC TD)\r
237         CyDmaChSetInitialTd(sdDMARxChan, sdDMARxTd[0]);\r
238         CyDmaChSetInitialTd(sdDMATxChan, sdDMATxTd[0]);\r
239 \r
240         // There is no flow control, so we must ensure we can read the bytes\r
241         // before we start transmitting\r
242         CyDmaChEnable(sdDMARxChan, 1);\r
243         CyDmaChEnable(sdDMATxChan, 1);\r
244 }\r
245 \r
246 int\r
247 sdReadSectorDMAPoll()\r
248 {\r
249         if (rxDMAComplete && txDMAComplete)\r
250         {\r
251                 // DMA transfer is complete\r
252                 dmaInProgress = 0;\r
253                 return 1;\r
254         }\r
255         else\r
256         {\r
257                 return 0;\r
258         }\r
259 }\r
260 \r
261 void sdReadSingleSectorDMA(uint32_t lba, uint8_t* outputBuffer)\r
262 {\r
263         uint8 v;\r
264         if (!sdDev.ccs)\r
265         {\r
266                 lba = lba * SD_SECTOR_SIZE;\r
267         }\r
268         v = sdCommandAndResponse(SD_READ_SINGLE_BLOCK, lba);\r
269         if (v)\r
270         {\r
271                 scsiDiskReset();\r
272                 sdClearStatus();\r
273 \r
274                 scsiDev.status = CHECK_CONDITION;\r
275                 scsiDev.sense.code = HARDWARE_ERROR;\r
276                 scsiDev.sense.asc = LOGICAL_UNIT_COMMUNICATION_FAILURE;\r
277                 scsiDev.phase = STATUS;\r
278         }\r
279         else\r
280         {\r
281                 dmaReadSector(outputBuffer);\r
282         }\r
283 }\r
284 \r
285 void\r
286 sdReadMultiSectorDMA(uint8_t* outputBuffer)\r
287 {\r
288         // Pre: sdReadMultiSectorPrep called.\r
289         dmaReadSector(outputBuffer);\r
290 }\r
291 \r
292 \r
293 void sdCompleteRead()\r
294 {\r
295         if (dmaInProgress)\r
296         {\r
297                 // Not much choice but to wait until we've completed the transfer.\r
298                 // Cancelling the transfer can't be done as we have no way to reset\r
299                 // the SD card.\r
300                 while (!sdReadSectorDMAPoll()) { /* spin */ }\r
301         }\r
302 \r
303         transfer.inProgress = 0;\r
304 \r
305         // We cannot send even a single "padding" byte, as we normally would when\r
306         // sending a command.  If we've just finished reading the very last block\r
307         // on the card, then reading an additional dummy byte will just trigger\r
308         // an error condition as we're trying to read past-the-end of the storage\r
309         // device.\r
310         // ie. do not use sdCommandAndResponse here.\r
311         uint8 r1b;\r
312         sdSendCommand(SD_STOP_TRANSMISSION, 0);\r
313         r1b = sdReadResp();\r
314 \r
315         if (r1b)\r
316         {\r
317                 // Try very hard to make sure the transmission stops\r
318                 int retries = 255;\r
319                 while (r1b && retries)\r
320                 {\r
321                         r1b = sdCommandAndResponse(SD_STOP_TRANSMISSION, 0);\r
322                         retries--;\r
323                 }\r
324 \r
325                 scsiDev.status = CHECK_CONDITION;\r
326                 scsiDev.sense.code = HARDWARE_ERROR;\r
327                 scsiDev.sense.asc = UNRECOVERED_READ_ERROR;\r
328                 scsiDev.phase = STATUS;\r
329         }\r
330 \r
331         // R1b has an optional trailing "busy" signal.\r
332         {\r
333                 uint8 busy;\r
334                 do\r
335                 {\r
336                         busy = sdSpiByte(0xFF);\r
337                 } while (busy == 0);\r
338         }\r
339 }\r
340 \r
341 static void sdWaitWriteBusy()\r
342 {\r
343         uint8 val;\r
344         do\r
345         {\r
346                 val = sdSpiByte(0xFF);\r
347         } while (val != 0xFF);\r
348 }\r
349 \r
350 void\r
351 sdWriteMultiSectorDMA(uint8_t* outputBuffer)\r
352 {\r
353         sdSpiByte(0xFC); // MULTIPLE byte start token\r
354 \r
355         // Transmit 512 bytes of data and then 2 bytes CRC.\r
356         CyDmaTdSetConfiguration(sdDMATxTd[0], SD_SECTOR_SIZE, sdDMATxTd[1], TD_INC_SRC_ADR);\r
357         CyDmaTdSetAddress(sdDMATxTd[0], LO16((uint32)outputBuffer), LO16((uint32)SDCard_TXDATA_PTR));\r
358         CyDmaTdSetConfiguration(sdDMATxTd[1], 2, CY_DMA_DISABLE_TD, SD_TX_DMA__TD_TERMOUT_EN);\r
359         CyDmaTdSetAddress(sdDMATxTd[1], LO16((uint32)&dummyBuffer), LO16((uint32)SDCard_TXDATA_PTR));\r
360 \r
361         CyDmaTdSetConfiguration(sdDMARxTd[0], SD_SECTOR_SIZE + 2, CY_DMA_DISABLE_TD, SD_RX_DMA__TD_TERMOUT_EN);\r
362         CyDmaTdSetAddress(sdDMARxTd[0], LO16((uint32)SDCard_RXDATA_PTR), LO16((uint32)&discardBuffer));\r
363 \r
364         \r
365         dmaInProgress = 1;\r
366         // The DMA controller is a bit trigger-happy. It will retain\r
367         // a drq request that was triggered while the channel was\r
368         // disabled.\r
369         CyDmaClearPendingDrq(sdDMATxChan);\r
370         CyDmaClearPendingDrq(sdDMARxChan);\r
371 \r
372         txDMAComplete = 0;\r
373         rxDMAComplete = 0;\r
374 \r
375         // Re-loading the initial TD's here is very important, or else\r
376         // we'll be re-using the last-used TD, which would be the last\r
377         // in the chain (ie. CRC TD)\r
378         CyDmaChSetInitialTd(sdDMARxChan, sdDMARxTd[0]);\r
379         CyDmaChSetInitialTd(sdDMATxChan, sdDMATxTd[0]);\r
380 \r
381         // There is no flow control, so we must ensure we can read the bytes\r
382         // before we start transmitting\r
383         CyDmaChEnable(sdDMARxChan, 1);\r
384         CyDmaChEnable(sdDMATxChan, 1);\r
385 }\r
386 \r
387 int\r
388 sdWriteSectorDMAPoll()\r
389 {\r
390         if (rxDMAComplete && txDMAComplete)\r
391         {\r
392                 uint8_t dataToken = sdSpiByte(0xFF); // Response\r
393                 if (dataToken == 0x0FF)\r
394                 {\r
395                         return 0; // Write has not completed.\r
396                 }\r
397                 else if (((dataToken & 0x1F) >> 1) != 0x2) // Accepted.\r
398                 {\r
399                         uint8 r1b, busy;\r
400                 \r
401                         sdWaitWriteBusy();\r
402 \r
403                         r1b = sdCommandAndResponse(SD_STOP_TRANSMISSION, 0);\r
404                         (void) r1b;\r
405                         sdSpiByte(0xFF);\r
406 \r
407                         // R1b has an optional trailing "busy" signal.\r
408                         do\r
409                         {\r
410                                 busy = sdSpiByte(0xFF);\r
411                         } while (busy == 0);\r
412 \r
413                         // Wait for the card to come out of busy.\r
414                         sdWaitWriteBusy();\r
415 \r
416                         transfer.inProgress = 0;\r
417                         scsiDiskReset();\r
418                         sdClearStatus();\r
419 \r
420                         scsiDev.status = CHECK_CONDITION;\r
421                         scsiDev.sense.code = HARDWARE_ERROR;\r
422                         scsiDev.sense.asc = LOGICAL_UNIT_COMMUNICATION_FAILURE;\r
423                         scsiDev.phase = STATUS;\r
424                 }\r
425                 else\r
426                 {\r
427                         sdWaitWriteBusy();\r
428                 }\r
429                 // DMA transfer is complete and the SD card has accepted the write.\r
430                 dmaInProgress = 0;\r
431 \r
432                 return 1;\r
433         }\r
434         else\r
435         {\r
436                 return 0;\r
437         }\r
438 }\r
439 \r
440 void sdCompleteWrite()\r
441 {\r
442         if (dmaInProgress)\r
443         {\r
444                 // Not much choice but to wait until we've completed the transfer.\r
445                 // Cancelling the transfer can't be done as we have no way to reset\r
446                 // the SD card.\r
447                 while (!sdWriteSectorDMAPoll()) { /* spin */ }\r
448         }\r
449         \r
450         transfer.inProgress = 0;\r
451 \r
452         uint8 r1, r2;\r
453 \r
454         sdSpiByte(0xFD); // STOP TOKEN\r
455         // Wait for the card to come out of busy.\r
456         sdWaitWriteBusy();\r
457 \r
458         r1 = sdCommandAndResponse(13, 0); // send status\r
459         r2 = sdSpiByte(0xFF);\r
460         if (r1 || r2)\r
461         {\r
462                 sdClearStatus();\r
463                 scsiDev.status = CHECK_CONDITION;\r
464                 scsiDev.sense.code = HARDWARE_ERROR;\r
465                 scsiDev.sense.asc = WRITE_ERROR_AUTO_REALLOCATION_FAILED;\r
466                 scsiDev.phase = STATUS;\r
467         }\r
468 }\r
469 \r
470 \r
471 // SD Version 2 (SDHC) support\r
472 static int sendIfCond()\r
473 {\r
474         int retries = 50;\r
475 \r
476         do\r
477         {\r
478                 // 11:8 Host voltage. 1 = 2.7-3.6V\r
479                 // 7:0 Echo bits. Ignore.\r
480                 uint8 status = sdCRCCommandAndResponse(SD_SEND_IF_COND, 0x000001AA);\r
481 \r
482                 if (status == SD_R1_IDLE)\r
483                 {\r
484                         // Version 2 card.\r
485                         sdDev.version = 2;\r
486                         // Read 32bit response. Should contain the same bytes that\r
487                         // we sent in the command parameter.\r
488                         sdSpiByte(0xFF);\r
489                         sdSpiByte(0xFF);\r
490                         sdSpiByte(0xFF);\r
491                         sdSpiByte(0xFF);\r
492                         break;\r
493                 }\r
494                 else if (status & SD_R1_ILLEGAL)\r
495                 {\r
496                         // Version 1 card.\r
497                         sdDev.version = 1;\r
498                         sdClearStatus();\r
499                         break;\r
500                 }\r
501 \r
502                 sdClearStatus();\r
503         } while (--retries > 0);\r
504 \r
505         return retries > 0;\r
506 }\r
507 \r
508 static int sdOpCond()\r
509 {\r
510         uint32_t start = getTime_ms();\r
511 \r
512         uint8 status;\r
513         do\r
514         {\r
515                 sdCRCCommandAndResponse(SD_APP_CMD, 0);\r
516                 // Host Capacity Support = 1 (SDHC/SDXC supported)\r
517                 status = sdCRCCommandAndResponse(SD_APP_SEND_OP_COND, 0x40000000);\r
518 \r
519                 sdClearStatus();\r
520 \r
521         // Spec says to poll for 1 second.\r
522         } while ((status != 0) && (diffTime_ms(start, getTime_ms()) < 1000));\r
523 \r
524         return status == 0;\r
525 }\r
526 \r
527 static int sdReadOCR()\r
528 {\r
529         uint32_t start = getTime_ms();\r
530         int complete;\r
531         uint8 status;\r
532         \r
533         do\r
534         {\r
535                 uint8 buf[4];\r
536                 int i;\r
537 \r
538                 status = sdCRCCommandAndResponse(SD_READ_OCR, 0);\r
539                 if(status) { break; }\r
540 \r
541                 for (i = 0; i < 4; ++i)\r
542                 {\r
543                         buf[i] = sdSpiByte(0xFF);\r
544                 }\r
545 \r
546                 sdDev.ccs = (buf[0] & 0x40) ? 1 : 0;\r
547                 complete = (buf[0] & 0x80);\r
548 \r
549         } while (!status &&\r
550                 !complete &&\r
551                 (diffTime_ms(start, getTime_ms()) < 1000));\r
552 \r
553         return (status == 0) && complete;\r
554 }\r
555 \r
556 static int sdReadCSD()\r
557 {\r
558         uint8 startToken;\r
559         int maxWait, i;\r
560         uint8 buf[16];\r
561 \r
562         uint8 status = sdCRCCommandAndResponse(SD_SEND_CSD, 0);\r
563         if(status){goto bad;}\r
564 \r
565         maxWait = 1023;\r
566         do\r
567         {\r
568                 startToken = sdSpiByte(0xFF);\r
569         } while(maxWait-- && (startToken != 0xFE));\r
570         if (startToken != 0xFE) { goto bad; }\r
571 \r
572         for (i = 0; i < 16; ++i)\r
573         {\r
574                 buf[i] = sdSpiByte(0xFF);\r
575         }\r
576         sdSpiByte(0xFF); // CRC\r
577         sdSpiByte(0xFF); // CRC\r
578 \r
579         if ((buf[0] >> 6) == 0x00)\r
580         {\r
581                 // CSD version 1\r
582                 // C_SIZE in bits [73:62]\r
583                 uint32 c_size = (((((uint32)buf[6]) & 0x3) << 16) | (((uint32)buf[7]) << 8) | buf[8]) >> 6;\r
584                 uint32 c_mult = (((((uint32)buf[9]) & 0x3) << 8) | ((uint32)buf[0xa])) >> 7;\r
585                 uint32 sectorSize = buf[5] & 0x0F;\r
586                 sdDev.capacity = ((c_size+1) * ((uint64)1 << (c_mult+2)) * ((uint64)1 << sectorSize)) / SD_SECTOR_SIZE;\r
587         }\r
588         else if ((buf[0] >> 6) == 0x01)\r
589         {\r
590                 // CSD version 2\r
591                 // C_SIZE in bits [69:48]\r
592 \r
593                 uint32 c_size =\r
594                         ((((uint32)buf[7]) & 0x3F) << 16) |\r
595                         (((uint32)buf[8]) << 8) |\r
596                         ((uint32)buf[7]);\r
597                 sdDev.capacity = (c_size + 1) * 1024;\r
598         }\r
599         else\r
600         {\r
601                 goto bad;\r
602         }\r
603 \r
604         return 1;\r
605 bad:\r
606         return 0;\r
607 }\r
608 \r
609 static void sdInitDMA()\r
610 {\r
611         // One-time init only.\r
612         if (sdDMATxChan == CY_DMA_INVALID_CHANNEL)\r
613         {\r
614                 sdDMATxChan =\r
615                         SD_TX_DMA_DmaInitialize(\r
616                                 1, // Bytes per burst\r
617                                 1, // request per burst\r
618                                 HI16(CYDEV_SRAM_BASE),\r
619                                 HI16(CYDEV_PERIPH_BASE)\r
620                                 );\r
621 \r
622                 sdDMARxChan =\r
623                         SD_RX_DMA_DmaInitialize(\r
624                                 1, // Bytes per burst\r
625                                 1, // request per burst\r
626                                 HI16(CYDEV_PERIPH_BASE),\r
627                                 HI16(CYDEV_SRAM_BASE)\r
628                                 );\r
629 \r
630                 CyDmaChDisable(sdDMATxChan);\r
631                 CyDmaChDisable(sdDMARxChan);\r
632 \r
633                 sdDMARxTd[0] = CyDmaTdAllocate();\r
634                 sdDMARxTd[1] = CyDmaTdAllocate();\r
635                 sdDMATxTd[0] = CyDmaTdAllocate();\r
636                 sdDMATxTd[1] = CyDmaTdAllocate();\r
637 \r
638                 SD_RX_DMA_COMPLETE_StartEx(sdRxISR);\r
639                 SD_TX_DMA_COMPLETE_StartEx(sdTxISR);\r
640         }\r
641 }\r
642 \r
643 int sdInit()\r
644 {\r
645         int result = 0;\r
646         int i;\r
647         uint8 v;\r
648 \r
649         sdDev.version = 0;\r
650         sdDev.ccs = 0;\r
651         sdDev.capacity = 0;\r
652 \r
653         sdInitDMA();\r
654 \r
655         SD_CS_Write(1); // Set CS inactive (active low)\r
656 \r
657         // Set the SPI clock for 400kHz transfers\r
658         // 25MHz / 400kHz approx factor of 63.\r
659         // The register contains (divider - 1)\r
660         uint16_t clkDiv25MHz =  SD_Data_Clk_GetDividerRegister();\r
661         SD_Data_Clk_SetDivider(((clkDiv25MHz + 1) * 63) - 1);\r
662         // Wait for the clock to settle.\r
663         CyDelayUs(1);\r
664 \r
665         SDCard_Start(); // Enable SPI hardware\r
666 \r
667         // Power on sequence. 74 clock cycles of a "1" while CS unasserted.\r
668         for (i = 0; i < 10; ++i)\r
669         {\r
670                 sdSpiByte(0xFF);\r
671         }\r
672 \r
673         SD_CS_Write(0); // Set CS active (active low)\r
674         CyDelayUs(1);\r
675 \r
676         v = sdCRCCommandAndResponse(SD_GO_IDLE_STATE, 0);\r
677         if(v != 1){goto bad;}\r
678 \r
679         ledOn();\r
680         if (!sendIfCond()) goto bad; // Sets V1 or V2 flag  CMD8\r
681         if (!sdOpCond()) goto bad; // ACMD41. Wait for init completes.\r
682         if (!sdReadOCR()) goto bad; // CMD58. Get CCS flag. Only valid after init.\r
683 \r
684         // This command will be ignored if sdDev.ccs is set.\r
685         // SDHC and SDXC are always 512bytes.\r
686         v = sdCRCCommandAndResponse(SD_SET_BLOCKLEN, SD_SECTOR_SIZE); //Force sector size\r
687         if(v){goto bad;}\r
688         v = sdCRCCommandAndResponse(SD_CRC_ON_OFF, 0); //crc off\r
689         if(v){goto bad;}\r
690 \r
691         // now set the sd card back to full speed.\r
692         // The SD Card spec says we can run SPI @ 25MHz\r
693         SDCard_Stop();\r
694 \r
695         // We can't run at full-speed with the pullup resistors enabled.\r
696         SD_MISO_SetDriveMode(SD_MISO_DM_DIG_HIZ);\r
697         SD_MOSI_SetDriveMode(SD_MOSI_DM_STRONG);\r
698         SD_SCK_SetDriveMode(SD_SCK_DM_STRONG);\r
699 \r
700         SD_Data_Clk_SetDivider(clkDiv25MHz);\r
701         CyDelayUs(1);\r
702         SDCard_Start();\r
703 \r
704         // Clear out rubbish data through clock change\r
705         CyDelayUs(1);\r
706         SDCard_ReadRxStatus();\r
707         SDCard_ReadTxStatus();\r
708         SDCard_ClearFIFO();\r
709 \r
710         if (!sdReadCSD()) goto bad;\r
711 \r
712         result = 1;\r
713         goto out;\r
714 \r
715 bad:\r
716         sdDev.capacity = 0;\r
717 \r
718 out:\r
719         sdClearStatus();\r
720         ledOff();\r
721         return result;\r
722 \r
723 }\r
724 \r
725 void sdWriteMultiSectorPrep()\r
726 {\r
727         uint8 v;\r
728         \r
729         // Set the number of blocks to pre-erase by the multiple block write command\r
730         // We don't care about the response - if the command is not accepted, writes\r
731         // will just be a bit slower.\r
732         // Max 22bit parameter.\r
733         uint32_t sdBlocks = transfer.blocks * SDSectorsPerSCSISector();\r
734         uint32 blocks = sdBlocks > 0x7FFFFF ? 0x7FFFFF : sdBlocks;\r
735         sdCommandAndResponse(SD_APP_CMD, 0);\r
736         sdCommandAndResponse(SD_APP_SET_WR_BLK_ERASE_COUNT, blocks);\r
737 \r
738         uint32 scsiLBA = (transfer.lba + transfer.currentBlock);\r
739         uint32 sdLBA = SCSISector2SD(scsiLBA);\r
740         if (!sdDev.ccs)\r
741         {\r
742                 sdLBA = sdLBA * SD_SECTOR_SIZE;\r
743         }\r
744         v = sdCommandAndResponse(25, sdLBA);\r
745         if (v)\r
746         {\r
747                 scsiDiskReset();\r
748                 sdClearStatus();\r
749                 scsiDev.status = CHECK_CONDITION;\r
750                 scsiDev.sense.code = HARDWARE_ERROR;\r
751                 scsiDev.sense.asc = LOGICAL_UNIT_COMMUNICATION_FAILURE;\r
752                 scsiDev.phase = STATUS;\r
753         }\r
754         else\r
755         {\r
756                 transfer.inProgress = 1;\r
757         }\r
758 }\r
759 \r