Merge Powerbook firmware updates
[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 \r
25 #include "scsiPhy.h"\r
26 \r
27 #include <string.h>\r
28 \r
29 // Global\r
30 SdDevice sdDev;\r
31 \r
32 // Private DMA variables.\r
33 static int dmaInProgress = 0;\r
34 static uint8 sdDMARxChan = CY_DMA_INVALID_CHANNEL;\r
35 static uint8 sdDMATxChan = CY_DMA_INVALID_CHANNEL;\r
36 \r
37 // DMA descriptors\r
38 static uint8 sdDMARxTd[2] = { CY_DMA_INVALID_TD, CY_DMA_INVALID_TD };\r
39 static uint8 sdDMATxTd[2] = { CY_DMA_INVALID_TD, CY_DMA_INVALID_TD };\r
40 \r
41 // Dummy location for DMA to send unchecked CRC bytes to\r
42 static uint8 discardBuffer;\r
43 \r
44 // Source of dummy SPI bytes for DMA\r
45 static uint8 dummyBuffer = 0xFF;\r
46 \r
47 volatile static uint8 rxDMAComplete;\r
48 volatile static uint8 txDMAComplete;\r
49 \r
50 CY_ISR_PROTO(sdRxISR);\r
51 CY_ISR(sdRxISR)\r
52 {\r
53         rxDMAComplete = 1;\r
54 }\r
55 CY_ISR_PROTO(sdTxISR);\r
56 CY_ISR(sdTxISR)\r
57 {\r
58         txDMAComplete = 1;\r
59 }\r
60 \r
61 static uint8 sdCrc7(uint8* chr, uint8 cnt, uint8 crc)\r
62 {\r
63         uint8 a;\r
64         for(a = 0; a < cnt; a++)\r
65         {\r
66                 uint8 Data = chr[a];\r
67                 uint8 i;\r
68                 for(i = 0; i < 8; i++)\r
69                 {\r
70                         crc <<= 1;\r
71                         if( (Data & 0x80) ^ (crc & 0x80) ) {crc ^= 0x09;}\r
72                         Data <<= 1;\r
73                 }\r
74         }\r
75         return crc & 0x7F;\r
76 }\r
77 \r
78 // Read and write 1 byte.\r
79 static uint8 sdSpiByte(uint8 value)\r
80 {\r
81         SDCard_WriteTxData(value);\r
82         while (!(SDCard_ReadRxStatus() & SDCard_STS_RX_FIFO_NOT_EMPTY)) {}\r
83         return SDCard_ReadRxData();\r
84 }\r
85 \r
86 static void sdSendCRCCommand(uint8 cmd, uint32 param)\r
87 {\r
88         uint8 send[6];\r
89 \r
90         send[0] = cmd | 0x40;\r
91         send[1] = param >> 24;\r
92         send[2] = param >> 16;\r
93         send[3] = param >> 8;\r
94         send[4] = param;\r
95         send[5] = (sdCrc7(send, 5, 0) << 1) | 1;\r
96 \r
97         for(cmd = 0; cmd < sizeof(send); cmd++)\r
98         {\r
99                 sdSpiByte(send[cmd]);\r
100         }\r
101         // Allow command to process before reading result code.\r
102         sdSpiByte(0xFF);\r
103 }\r
104 \r
105 static void sdSendCommand(uint8 cmd, uint32 param)\r
106 {\r
107         uint8 send[6];\r
108 \r
109         send[0] = cmd | 0x40;\r
110         send[1] = param >> 24;\r
111         send[2] = param >> 16;\r
112         send[3] = param >> 8;\r
113         send[4] = param;\r
114         send[5] = 0;\r
115 \r
116         for(cmd = 0; cmd < sizeof(send); cmd++)\r
117         {\r
118                 sdSpiByte(send[cmd]);\r
119         }\r
120         // Allow command to process before reading result code.\r
121         sdSpiByte(0xFF);\r
122 }\r
123 \r
124 static uint8 sdReadResp()\r
125 {\r
126         uint8 v;\r
127         uint8 i = 128;\r
128         do\r
129         {\r
130                 v = sdSpiByte(0xFF);\r
131         } while(i-- && (v & 0x80));\r
132         return v;\r
133 }\r
134 \r
135 static uint8 sdCommandAndResponse(uint8 cmd, uint32 param)\r
136 {\r
137         sdSpiByte(0xFF);\r
138         sdSendCommand(cmd, param);\r
139         return sdReadResp();\r
140 }\r
141 \r
142 static uint8 sdCRCCommandAndResponse(uint8 cmd, uint32 param)\r
143 {\r
144         sdSpiByte(0xFF);\r
145         sdSendCRCCommand(cmd, param);\r
146         return sdReadResp();\r
147 }\r
148 \r
149 // Clear the sticky status bits on error.\r
150 static void sdClearStatus()\r
151 {\r
152         uint8 r2hi = sdCRCCommandAndResponse(SD_SEND_STATUS, 0);\r
153         uint8 r2lo = sdSpiByte(0xFF);\r
154         (void) r2hi; (void) r2lo;\r
155 }\r
156 \r
157 \r
158 void\r
159 sdReadMultiSectorPrep()\r
160 {\r
161         uint8 v;\r
162         uint32 scsiLBA = (transfer.lba + transfer.currentBlock);\r
163         uint32 sdLBA = SCSISector2SD(scsiLBA);\r
164 \r
165         if (!sdDev.ccs)\r
166         {\r
167                 sdLBA = sdLBA * SD_SECTOR_SIZE;\r
168         }\r
169         v = sdCommandAndResponse(SD_READ_MULTIPLE_BLOCK, sdLBA);\r
170         if (v)\r
171         {\r
172                 scsiDiskReset();\r
173                 sdClearStatus();\r
174 \r
175                 scsiDev.status = CHECK_CONDITION;\r
176                 scsiDev.sense.code = HARDWARE_ERROR;\r
177                 scsiDev.sense.asc = LOGICAL_UNIT_COMMUNICATION_FAILURE;\r
178                 scsiDev.phase = STATUS;\r
179         }\r
180         else\r
181         {\r
182                 transfer.inProgress = 1;\r
183         }\r
184 }\r
185 \r
186 static void\r
187 dmaReadSector(uint8_t* outputBuffer)\r
188 {\r
189         // Wait for a start-block token.\r
190         // Don't wait more than 100ms, which is the timeout recommended\r
191         // in the standard.\r
192         //100ms @ 64Hz = 6400000\r
193         int maxWait = 6400000;\r
194         uint8 token = sdSpiByte(0xFF);\r
195         while (token != 0xFE && (maxWait-- > 0))\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                 uint8 status = sdCRCCommandAndResponse(SD_SEND_IF_COND, 0x000001AA);\r
479 \r
480                 if (status == SD_R1_IDLE)\r
481                 {\r
482                         // Version 2 card.\r
483                         sdDev.version = 2;\r
484                         // Read 32bit response. Should contain the same bytes that\r
485                         // we sent in the command parameter.\r
486                         sdSpiByte(0xFF);\r
487                         sdSpiByte(0xFF);\r
488                         sdSpiByte(0xFF);\r
489                         sdSpiByte(0xFF);\r
490                         break;\r
491                 }\r
492                 else if (status & SD_R1_ILLEGAL)\r
493                 {\r
494                         // Version 1 card.\r
495                         sdDev.version = 1;\r
496                         sdClearStatus();\r
497                         break;\r
498                 }\r
499 \r
500                 sdClearStatus();\r
501         } while (--retries > 0);\r
502 \r
503         return retries > 0;\r
504 }\r
505 \r
506 static int sdOpCond()\r
507 {\r
508         int retries = 50;\r
509 \r
510         uint8 status;\r
511         do\r
512         {\r
513                 CyDelay(33); // Spec says to retry for 1 second.\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         } while ((status != 0) && (--retries > 0));\r
521 \r
522         return retries > 0;\r
523 }\r
524 \r
525 static int sdReadOCR()\r
526 {\r
527         uint8 buf[4];\r
528         int i;\r
529         \r
530         uint8 status = sdCRCCommandAndResponse(SD_READ_OCR, 0);\r
531         if(status){goto bad;}\r
532 \r
533         for (i = 0; i < 4; ++i)\r
534         {\r
535                 buf[i] = sdSpiByte(0xFF);\r
536         }\r
537 \r
538         sdDev.ccs = (buf[0] & 0x40) ? 1 : 0;\r
539 \r
540         return 1;\r
541 bad:\r
542         return 0;\r
543 }\r
544 \r
545 static int sdReadCSD()\r
546 {\r
547         uint8 startToken;\r
548         int maxWait, i;\r
549         uint8 buf[16];\r
550         \r
551         uint8 status = sdCRCCommandAndResponse(SD_SEND_CSD, 0);\r
552         if(status){goto bad;}\r
553 \r
554         maxWait = 1023;\r
555         do\r
556         {\r
557                 startToken = sdSpiByte(0xFF);\r
558         } while(maxWait-- && (startToken != 0xFE));\r
559         if (startToken != 0xFE) { goto bad; }\r
560 \r
561         for (i = 0; i < 16; ++i)\r
562         {\r
563                 buf[i] = sdSpiByte(0xFF);\r
564         }\r
565         sdSpiByte(0xFF); // CRC\r
566         sdSpiByte(0xFF); // CRC\r
567 \r
568         if ((buf[0] >> 6) == 0x00)\r
569         {\r
570                 // CSD version 1\r
571                 // C_SIZE in bits [73:62]\r
572                 uint32 c_size = (((((uint32)buf[6]) & 0x3) << 16) | (((uint32)buf[7]) << 8) | buf[8]) >> 6;\r
573                 uint32 c_mult = (((((uint32)buf[9]) & 0x3) << 8) | ((uint32)buf[0xa])) >> 7;\r
574                 uint32 sectorSize = buf[5] & 0x0F;\r
575                 sdDev.capacity = ((c_size+1) * ((uint64)1 << (c_mult+2)) * ((uint64)1 << sectorSize)) / SD_SECTOR_SIZE;\r
576         }\r
577         else if ((buf[0] >> 6) == 0x01)\r
578         {\r
579                 // CSD version 2\r
580                 // C_SIZE in bits [69:48]\r
581 \r
582                 uint32 c_size =\r
583                         ((((uint32)buf[7]) & 0x3F) << 16) |\r
584                         (((uint32)buf[8]) << 8) |\r
585                         ((uint32)buf[7]);\r
586                 sdDev.capacity = (c_size + 1) * 1024;\r
587         }\r
588         else\r
589         {\r
590                 goto bad;\r
591         }\r
592 \r
593         return 1;\r
594 bad:\r
595         return 0;\r
596 }\r
597 \r
598 static void sdInitDMA()\r
599 {\r
600         // One-time init only.\r
601         if (sdDMATxChan == CY_DMA_INVALID_CHANNEL)\r
602         {\r
603                 sdDMATxChan =\r
604                         SD_TX_DMA_DmaInitialize(\r
605                                 1, // Bytes per burst\r
606                                 1, // request per burst\r
607                                 HI16(CYDEV_SRAM_BASE),\r
608                                 HI16(CYDEV_PERIPH_BASE)\r
609                                 );\r
610 \r
611                 sdDMARxChan =\r
612                         SD_RX_DMA_DmaInitialize(\r
613                                 1, // Bytes per burst\r
614                                 1, // request per burst\r
615                                 HI16(CYDEV_PERIPH_BASE),\r
616                                 HI16(CYDEV_SRAM_BASE)\r
617                                 );\r
618 \r
619                 CyDmaChDisable(sdDMATxChan);\r
620                 CyDmaChDisable(sdDMARxChan);\r
621 \r
622                 sdDMARxTd[0] = CyDmaTdAllocate();\r
623                 sdDMARxTd[1] = CyDmaTdAllocate();\r
624                 sdDMATxTd[0] = CyDmaTdAllocate();\r
625                 sdDMATxTd[1] = CyDmaTdAllocate();\r
626 \r
627                 SD_RX_DMA_COMPLETE_StartEx(sdRxISR);\r
628                 SD_TX_DMA_COMPLETE_StartEx(sdTxISR);\r
629         }\r
630 }\r
631 \r
632 int sdInit()\r
633 {\r
634         int result = 0;\r
635         int i;\r
636         uint8 v;\r
637         \r
638         sdDev.version = 0;\r
639         sdDev.ccs = 0;\r
640         sdDev.capacity = 0;\r
641 \r
642         sdInitDMA();\r
643 \r
644         SD_CS_Write(1); // Set CS inactive (active low)\r
645 \r
646         // Set the SPI clock for 400kHz transfers\r
647         // 25MHz / 400kHz approx factor of 63.\r
648         // The register contains (divider - 1)\r
649         uint16_t clkDiv25MHz =  SD_Data_Clk_GetDividerRegister();\r
650         SD_Data_Clk_SetDivider(((clkDiv25MHz + 1) * 63) - 1);\r
651         // Wait for the clock to settle.\r
652         CyDelayUs(1);\r
653 \r
654         SDCard_Start(); // Enable SPI hardware\r
655 \r
656         // Power on sequence. 74 clock cycles of a "1" while CS unasserted.\r
657         for (i = 0; i < 10; ++i)\r
658         {\r
659                 sdSpiByte(0xFF);\r
660         }\r
661 \r
662         SD_CS_Write(0); // Set CS active (active low)\r
663         CyDelayUs(1);\r
664 \r
665         v = sdCRCCommandAndResponse(SD_GO_IDLE_STATE, 0);\r
666         if(v != 1){goto bad;}\r
667 \r
668         ledOn();\r
669         if (!sendIfCond()) goto bad; // Sets V1 or V2 flag\r
670         if (!sdOpCond()) goto bad;\r
671         if (!sdReadOCR()) goto bad;\r
672 \r
673         // This command will be ignored if sdDev.ccs is set.\r
674         // SDHC and SDXC are always 512bytes.\r
675         v = sdCRCCommandAndResponse(SD_SET_BLOCKLEN, SD_SECTOR_SIZE); //Force sector size\r
676         if(v){goto bad;}\r
677         v = sdCRCCommandAndResponse(SD_CRC_ON_OFF, 0); //crc off\r
678         if(v){goto bad;}\r
679 \r
680         // now set the sd card back to full speed.\r
681         // The SD Card spec says we can run SPI @ 25MHz\r
682         SDCard_Stop();\r
683 \r
684         // We can't run at full-speed with the pullup resistors enabled.\r
685         SD_MISO_SetDriveMode(SD_MISO_DM_DIG_HIZ);\r
686         SD_MOSI_SetDriveMode(SD_MOSI_DM_STRONG);\r
687         SD_SCK_SetDriveMode(SD_SCK_DM_STRONG);\r
688 \r
689         SD_Data_Clk_SetDivider(clkDiv25MHz);\r
690         CyDelayUs(1);\r
691         SDCard_Start();\r
692 \r
693         // Clear out rubbish data through clock change\r
694         CyDelayUs(1);\r
695         SDCard_ReadRxStatus();\r
696         SDCard_ReadTxStatus();\r
697         SDCard_ClearFIFO();\r
698 \r
699         if (!sdReadCSD()) goto bad;\r
700 \r
701         result = 1;\r
702         goto out;\r
703 \r
704 bad:\r
705         sdDev.capacity = 0;\r
706 \r
707 out:\r
708         sdClearStatus();\r
709         ledOff();\r
710         return result;\r
711 \r
712 }\r
713 \r
714 void sdWriteMultiSectorPrep()\r
715 {\r
716         uint8 v;\r
717         \r
718         // Set the number of blocks to pre-erase by the multiple block write command\r
719         // We don't care about the response - if the command is not accepted, writes\r
720         // will just be a bit slower.\r
721         // Max 22bit parameter.\r
722         uint32_t sdBlocks = transfer.blocks * SDSectorsPerSCSISector();\r
723         uint32 blocks = sdBlocks > 0x7FFFFF ? 0x7FFFFF : sdBlocks;\r
724         sdCommandAndResponse(SD_APP_CMD, 0);\r
725         sdCommandAndResponse(SD_APP_SET_WR_BLK_ERASE_COUNT, blocks);\r
726 \r
727         uint32 scsiLBA = (transfer.lba + transfer.currentBlock);\r
728         uint32 sdLBA = SCSISector2SD(scsiLBA);\r
729         if (!sdDev.ccs)\r
730         {\r
731                 sdLBA = sdLBA * SD_SECTOR_SIZE;\r
732         }\r
733         v = sdCommandAndResponse(25, sdLBA);\r
734         if (v)\r
735         {\r
736                 scsiDiskReset();\r
737                 sdClearStatus();\r
738                 scsiDev.status = CHECK_CONDITION;\r
739                 scsiDev.sense.code = HARDWARE_ERROR;\r
740                 scsiDev.sense.asc = LOGICAL_UNIT_COMMUNICATION_FAILURE;\r
741                 scsiDev.phase = STATUS;\r
742         }\r
743         else\r
744         {\r
745                 transfer.inProgress = 1;\r
746         }\r
747 }\r
748 \r