changing circuitry to disable RTC, update initialization to match
[fw/openalt] / fatfs / mmc.c
1 /*************************************************************************
2  *
3  *    Used with ICCARM and AARM.
4  *
5  *    (c) Copyright IAR Systems 2005
6  *
7  *    File name   : mmc.c
8  *    Description : MMC
9  *
10  *    History :
11  *    1. Data        : July 1, 2005
12  *       Author      : Stanimir Bonev
13  *       Description : Create
14  *
15  *    $Revision: 1.4 $
16  *
17  * (C) Joel Winarske, 2006,2007                                        
18 **************************************************************************/
19 #include <stdio.h> // ###
20 #include "disk.h"
21 #include "diskio.h"
22 #include "mmc.h"
23 #include "spi.h"
24
25 #define MMC_RET_ERROR(Res)          do { mmcLastError = Res; return (MmcCardError); } while (0)
26 #define MMC_RET_DATA_ERR(Res)       do { mmcLastError = Res; return (MmcDataError); } while (0)
27
28 #define CSD_GET_TRAN_SPEED_EXP()      (mmcSdCsd [ 3] & 0x07)
29 #define CSD_GET_TRAN_SPEED_MANT()    ((mmcSdCsd [ 3] & 0xF8) >> 3)
30 #define CSD_GET_NSAC()                (mmcSdCsd [ 2])
31 #define CSD_GET_TAAC_EXP()            (mmcSdCsd [ 1] & 0x7)
32 #define CSD_GET_TAAC_MANT()          ((mmcSdCsd [ 1] & 0xF8) >> 3)
33 #define CSD_GET_R2W_FACTOR()         ((mmcSdCsd [12] & 0x1C) >> 2)
34 #define CSD_GET_READ_BL_LEN()         (mmcSdCsd [ 5] & 0x0F)
35 #define CSD_GET_C_SIZE()            (((mmcSdCsd [ 6] & 0x03) << 10) + (mmcSdCsd [7] << 2) + ((mmcSdCsd [8] & 0xc0) >> 6))
36 #define CSD_GET_C_SIZE_MULT()       (((mmcSdCsd [ 9] & 0x03) << 1) + ((mmcSdCsd [10] & 0x80) >> 7))
37 #define CSD_GET_PERM_WRITE_PROTECT() ((mmcSdCsd [14] & 0x20) >> 5)
38 #define CSD_GET_TMP_WRITE_PROTECT()  ((mmcSdCsd [14] & 0x10) >> 4)
39
40 static const U32 mmcTransfExp [] =
41 {
42      10000UL,
43     100000UL,
44    1000000UL,
45   10000000UL,
46          0UL,
47          0UL,
48          0UL,
49          0UL,
50 };
51
52 static const U32 mmmcAccessTime [] =
53 {
54  10000000UL,
55   1000000UL,
56    100000UL,
57     10000UL,
58      1000UL,
59       100UL,
60        10UL,
61         1UL,
62 };
63
64 static const U32 mmcCsdMant [] =
65 {
66   0UL,10UL,12UL,13UL,15UL,
67   20UL,25UL,
68   30UL,35UL,
69   40UL,45UL,
70   50UL,55UL,
71   60UL,
72   70UL,
73   80UL,
74 };
75
76 static const U32 mmcAccessTimeMant [] =
77 {
78   0UL,100UL,83UL,77UL,67UL,
79   50UL,40UL,
80   33UL,29UL,
81   25UL,22UL,
82   20UL,18UL,
83   17UL,
84   14UL,
85   13UL,
86 };
87
88 static const mmcCommads_t mmcCmd [CMD_END] =
89 {
90   { 0x40, MmcNoArg,     MmcR1 }, // CMD0
91   { 0x41, MmcNoArg,     MmcR1 }, // CMD1
92   { 0x49, MmcNoArg,     MmcR1 }, // CMD9
93   { 0x4A, MmcNoArg,     MmcR1 }, // CMD10
94   { 0x4C, MmcNoArg,     MmcR1 }, // CMD12
95   { 0x4D, MmcNoArg,     MmcR2 }, // CMD13
96   { 0x50, MmcBlockLen,  MmcR1 }, // CMD16
97   { 0x51, MmcDataAdd,   MmcR1 }, // CMD17
98   { 0x52, MmcDataAdd,   MmcR1 }, // CMD18
99   { 0x58, MmcDataAdd,   MmcR1 }, // CMD24
100   { 0x59, MmcDataAdd,   MmcR1 }, // CMD25
101   { 0x5B, MmcNoArg,     MmcR1 }, // CMD27
102   { 0x5C, MmcDataAdd,   MmcR1b}, // CMD28
103   { 0x5D, MmcDataAdd,   MmcR1b}, // CMD29
104   { 0x5E, MmcDataAdd,   MmcR1 }, // CMD30
105   { 0x60, MmcDataAdd,   MmcR1 }, // CMD32
106   { 0x61, MmcDataAdd,   MmcR1 }, // CMD33
107   { 0x62, MmcDataAdd,   MmcR1 }, // CMD34
108   { 0x63, MmcDataAdd,   MmcR1 }, // CMD35
109   { 0x64, MmcDataAdd,   MmcR1 }, // CMD36
110   { 0x65, MmcDataAdd,   MmcR1 }, // CMD37
111   { 0x66, MmcDummyWord, MmcR1b}, // CMD38
112   { 0x6A, MmcDummyWord, MmcR1b}, // CMD42
113   { 0x77, MmcNoArg,     MmcR1 }, // CMD55
114   { 0x78, MmcNoArg,     MmcR1 }, // CMD56
115   { 0x7A, MmcNoArg,     MmcR3 }, // CMD58
116   { 0x7B, MmcDummyWord, MmcR1 }, // CMD59
117   { 0x69, MmcNoArg,     MmcR1 } // ACMD41
118 };
119
120 static volatile DSTATUS Stat = STA_NOINIT;  /* Disk status */
121 static DiskStatus_t mmcDskStatus;
122 static U32 mmcLastError; 
123 static U32 Tnac;
124 static U32 Twr;
125 static U8 mmcSdCsd [16];
126
127 //
128 //
129 //
130 static U32 mmcSendCmd (mmcSpiCmdInd_t ComdInd, U32 Arg);
131 static U32 mmcSetBlockLen (U32 length);
132 static void mmcCSDImplement (void);
133 static mmcState_t mmcInitMedia (void);
134 static mmcState_t mmcReadCardInfo (U8 *pData, mmcSpiCmdInd_t Command);
135 static inline mmcState_t mmcRead (U8 *pData, U32 Add, U32 Length);
136 static inline mmcState_t mmcWrite (U8 *pData, U32 Add, U32 Length);
137 static inline mmcState_t mmcVerify (U8 *pData, U32 Add, U32 Length);
138
139 /*************************************************************************
140  * Function Name: mmcSendCmd
141  * Parameters: MmcSpiCmdInd_t ComdInd,U32 Arg
142  *
143  * Return: U32
144  *
145  * Description: MMC commands implemet
146  *
147  *************************************************************************/
148 static U32 mmcSendCmd (mmcSpiCmdInd_t ComdInd, U32 Arg)
149 {
150   U32 ch = 0xff;
151   U32 i;
152
153   //
154   //  Chip Select
155   //
156   spiChipSelect (1);
157
158   //
159   //  Send command code
160   //
161   spiTransferByte (mmcCmd [ComdInd].TxData);
162
163   //
164   //  Send command's arguments
165   //
166   if (mmcCmd [ComdInd].Arg == MmcNoArg)
167   {
168     spiTransferByte (0x00);
169     spiTransferByte (0x00);
170     spiTransferByte (0x00);
171     spiTransferByte (0x00);
172   }
173   else
174   {
175     spiTransferByte (Arg >> 24);
176     spiTransferByte (Arg >> 16);
177     spiTransferByte (Arg >> 8);
178     spiTransferByte (Arg);
179   }
180
181   //
182   //  Send CRC
183   //
184   if (ComdInd == CMD0)
185     spiTransferByte (0x95);
186   else
187     spiTransferByte (0xff);
188
189   for (i = 9; i && (ch == 0xff); --i) 
190     ch = spiTransferByte (0xff);
191
192   if (i == 0)
193   {
194     spiChipSelect (0);
195     return ((U32) -1);
196   }
197
198   switch (mmcCmd [ComdInd].Resp)
199   {
200     case MmcR1b :
201       {
202         U32 busy;
203
204         for (busy = 0, i = Twr; i && (busy != 0xff); --i)
205           busy = spiTransferByte (0xff);
206       }
207       return (ch);
208
209     case MmcR1 :
210       return (ch);
211
212     case MmcR2 :
213       Arg  = ((U32) ch << 8) & 0x0000FF00;
214       Arg |= spiTransferByte (0xff) & 0xff;
215       return (Arg);
216
217     case MmcR3 :
218     default:
219       Arg  = ((U32) ch << 24) & 0xff000000;
220       Arg |= ((U32) spiTransferByte (0xff) << 16) & 0x00FF0000;
221       Arg |= ((U32) spiTransferByte (0xff) << 8 ) & 0x0000FF00;
222       Arg |= spiTransferByte (0xff) & 0xff;
223       return (Arg);
224   }
225 }
226
227 /*************************************************************************
228  * Function Name: mmcSetBlockLen
229  * Parameters: U32 Length
230  *
231  * Return: U32
232  *
233  * Description: Set Block length Return command's result
234  *
235  *************************************************************************/
236 static U32 mmcSetBlockLen (U32 length)
237 {
238   U32 res = mmcSendCmd (CMD16, length);
239   spiChipSelect (0);
240   return (res);
241 }
242
243 /*************************************************************************
244  * Function Name: mmcCSDImplement
245  * Parameters:  none
246  *
247  * Return: none
248  *
249  * Description: Implemet data from CSD
250  *
251  *************************************************************************/
252 static void mmcCSDImplement (void)
253 {
254   U32 frequency;
255
256   //
257   // Calculate SPI max clock
258   //
259   frequency = mmcTransfExp [CSD_GET_TRAN_SPEED_EXP ()] * mmcCsdMant [CSD_GET_TRAN_SPEED_MANT ()];
260
261   if (frequency > 20000000)
262     frequency = 20000000;
263
264   frequency = spiSetClockFreq (frequency);
265
266   if (mmcDskStatus.DiskType == DiskMMC)
267   {
268     Tnac = mmmcAccessTime [CSD_GET_TAAC_EXP ()] * mmcAccessTimeMant [CSD_GET_TAAC_MANT ()];
269     Tnac = frequency / Tnac;
270     Tnac += 1 << (CSD_GET_NSAC () + 4);
271     Tnac *= 10;
272     Twr   = Tnac * CSD_GET_R2W_FACTOR ();
273   }
274   else
275   {
276     Tnac = frequency / SD_READ_TIME_OUT;
277     Twr  = frequency / SD_WRITE_TIME_OUT;
278   }
279
280   mmcDskStatus.BlockSize = 1 << CSD_GET_READ_BL_LEN ();
281   mmcDskStatus.BlockNumb = (CSD_GET_C_SIZE () + 1) * (4 << CSD_GET_C_SIZE_MULT ());
282   mmcDskStatus.WriteProtect = spiWriteProtect () | CSD_GET_PERM_WRITE_PROTECT () | CSD_GET_TMP_WRITE_PROTECT ();
283 }
284
285 /*************************************************************************
286  * Function Name: mmcInitMedia
287  * Parameters: none
288  *
289  * Return: mmcState_t
290  *
291  * Description: MMC detect and initialize
292  *
293  *************************************************************************/
294 static mmcState_t mmcInitMedia (void)
295 {
296   U32 i;
297   U32 res;
298
299   Tnac = 1;
300
301   if (!spiPresent ())
302     return (MmcNoPresent);
303
304   //
305   //  Clock Freq. Identification Mode < 400kHz
306   //
307   spiSetClockFreq (IdentificationModeClock);
308
309   //
310   //  Set maximum time out
311   //
312   Tnac = IdentificationModeClock / SD_READ_TIME_OUT;
313
314   //
315   //  Power up cycles.  After power up at least 74 clock cycles are required 
316   //  prior to starting bus communication
317   //
318   for (i = 0; i < 2; i++)
319   {
320     spiChipSelect (0);
321
322     for (res = 10; res; --res)
323       spiTransferByte (0xff);
324
325     //
326     //  CMD0 (Go to IDLE) to put MMC in SPI mode
327     //
328     res = mmcSendCmd (CMD0, 0);
329     spiChipSelect (0);
330
331     if (res == MMC_IDLE_STATE)
332       break;
333   }
334
335   if (res != MMC_IDLE_STATE)
336     return (MmcNoResponse);
337
338   //
339   //  Determinate Card type SD or MMC
340   //
341   mmcDskStatus.DiskType = DiskMMC;
342
343   for (i = 100; i; --i)
344   {
345     spiChipSelect (0);
346     spiTransferByte (0xff);
347     res = mmcSendCmd (CMD55, 0);
348     spiChipSelect (0);
349     spiChipSelect (0);
350     spiTransferByte (0xff);
351     res = mmcSendCmd (ACMD41, 0);
352     spiChipSelect (0);
353
354     if (res & MMC_ILLEGAL_CMD)
355     {
356       //
357       //  MMC card may be CMD1 for MMC Init sequence will be complete within 500ms
358       //
359       for (i = 100; i; --i)
360       {
361         spiChipSelect (0);
362         spiTransferByte (0xff);
363         res = mmcSendCmd (CMD1, 0);
364         spiChipSelect (0);
365
366         if (res == MMC_OK)
367           break;
368
369         spiDelay1ms (50);
370       }
371       break;
372     }
373
374     if (res == MMC_OK)
375     {
376       mmcDskStatus.DiskType = DiskSD;
377       break;
378     }
379
380     spiDelay1ms (50);
381   }
382
383   if (i == 0)
384     return (MmcNoResponse);
385
386   //
387   //  Read CSD.  CSD must always be valid
388   //
389   if ((res = mmcReadCardInfo (mmcSdCsd, CMD9)) != MmcOk)
390     return (MmcNoResponse);
391
392   //
393   //  Implement CSD data, and set block size
394   //
395   mmcCSDImplement ();
396   mmcSetBlockLen (mmcDskStatus.BlockSize);
397
398   // mmcDecode (mmcSdCsd); // ###
399
400   return (MmcOk);
401 }
402
403 /*************************************************************************
404  * Function Name: mmcReadCardInfo
405  * Parameters: U8 *pData,
406  *             mmcSpiCmdInd_t Command - CMD9, CMD10 are only allowed
407  *
408  * Return: mmcState_t
409  *
410  * Description: Read CSD or CID  registers depend of commoand
411  *
412  *************************************************************************/
413 static mmcState_t mmcReadCardInfo (U8 *pData, mmcSpiCmdInd_t Command)
414 {
415   U32 i;
416   U32 res;
417
418   switch (Command)
419   {
420     case CMD9 :
421     case CMD10 :
422       break;
423
424     default:
425       return (MmmcParameterError);
426   }
427
428   spiChipSelect (0);
429   spiTransferByte (0xff);
430
431   if ((res = mmcSendCmd (Command, 0)) == MMC_OK)
432   {
433     for (i = 8; i ; --i)
434     {
435       if (((res = spiTransferByte (0xff)) | MMC_DATA_ERR_TOKEN) == MMC_DATA_ERR_TOKEN)
436       {
437         // printf ("line %d: spiTransferByte returned 0x%x\n", __LINE__, res); // ###
438         MMC_RET_DATA_ERR (res);
439       }
440       else if (res == MMC_DATA_TOKEN)
441       {
442         for (i = 0; i <16 ; ++i)
443           *pData++ = spiTransferByte (0xff);
444
445         //
446         // CRC receive
447         //
448         spiTransferByte (0xff);
449         spiTransferByte (0xff);
450         spiChipSelect (0);
451         return (MmcOk);
452       }
453     }
454   }
455   // else
456   //   printf ("line %d: mmcSendCmd returned %d\n", __LINE__, res); // ###
457
458   spiChipSelect (0);
459   MMC_RET_ERROR (res);
460 }
461
462 /*************************************************************************
463  * Function Name: mmcRead
464  * Parameters: U8 *pData, U32 Add, U32 Length
465  *
466  * Return: mmcState_t
467  *
468  * Description: Read from a MMC
469  *
470  *************************************************************************/
471 static inline mmcState_t mmcRead (U8 *pData, U32 Add, U32 Length)
472 {
473   U32 res;
474   U32 i;
475
476   //
477   //  For synchronization
478   //
479   spiChipSelect (0);
480   spiTransferByte (0xff);
481   res = mmcSendCmd (CMD17, Add);
482
483   if (res == MMC_OK)
484   {
485     for (i = Tnac; i; --i)
486     {
487       res = spiTransferByte (0xff);
488
489       if ((res | MMC_DATA_ERR_TOKEN) == MMC_DATA_ERR_TOKEN)
490         MMC_RET_DATA_ERR (res);
491       else if (res == MMC_DATA_TOKEN)
492       {
493         spiReceiveBlock (pData, Length);
494
495         //
496         //  CRC receive
497         //
498         spiTransferByte (0xff);
499         spiTransferByte (0xff);
500         spiChipSelect (0);
501         return (MmcOk);
502       }
503     }
504
505     spiChipSelect (0);
506     return (MmcNoResponse);
507   }
508
509   spiChipSelect (0);
510   MMC_RET_ERROR (res);
511 }
512
513 /*************************************************************************
514  * Function Name: mmcWrite
515  * Parameters: U8 *pData, U32 Add, U32 Length
516  *
517  * Return: mmcState_t
518  *
519  * Description: Write to a MMC
520  *
521  *************************************************************************/
522 static inline mmcState_t mmcWrite (U8 *pData, U32 Add, U32 Length)
523 {
524   U32 res;
525   U32 i;
526
527   //
528   //  For synchronization
529   //
530   spiChipSelect (0);
531   spiTransferByte (0xff);
532
533   if ((res = mmcSendCmd (CMD24, Add)) == MMC_OK)
534   {
535     spiTransferByte (0xff);
536     spiTransferByte (MMC_DATA_TOKEN);
537     spiSendBlock (pData, Length);
538
539     //
540     //  CRC Send
541     //
542     spiTransferByte (0xff);
543     spiTransferByte (0xff);
544
545     if ((spiTransferByte (0xff) & 0x1F) != 0x05)
546       MMC_RET_ERROR (res);
547
548     for (i = Twr; i ;i--)
549       if (spiTransferByte (0xff) == 0xff)
550         break;
551     
552     spiChipSelect (0);
553
554     if (i == 0)
555       return (MmcNoResponse);
556
557     return (MmcOk);
558   }
559
560   spiChipSelect (0);
561   MMC_RET_ERROR (res);
562 }
563
564 /*************************************************************************
565  * Function Name: mmcVerify
566  * Parameters: U8 *pData, U32 Add, U32 Length
567  *
568  * Return: mmcState_t
569  *
570  * Description: Verify on a MMC
571  *
572  *************************************************************************/
573 static inline mmcState_t mmcVerify (U8 *pData, U32 Add, U32 Length)
574 {
575   U32 res,i;
576
577   //
578   //  For synchronization
579   //
580   spiChipSelect (0);
581   spiTransferByte (0xff);
582
583   if ((res = mmcSendCmd (CMD17, Add)) == MMC_OK)
584   {
585     for (i = Tnac; i; --i)
586     {
587       res = spiTransferByte (0xff);
588
589       if ((res | MMC_DATA_ERR_TOKEN) == MMC_DATA_ERR_TOKEN)
590         MMC_RET_DATA_ERR (res);
591       else if (res == MMC_DATA_TOKEN)
592       {
593         for (res = 0, i = 0; i < Length; ++i, ++pData)
594         {
595           *pData ^= spiTransferByte (0xff);
596
597           if (*pData != 0)
598             res = 1;
599         }
600
601         //
602         //  CRC receive
603         //
604         spiTransferByte (0xff);
605         spiTransferByte (0xff);
606         spiChipSelect (0);
607         spiTransferByte (0xff);
608         spiTransferByte (0xff);
609
610         if (res)
611           return (MmcMiscompare);
612
613         return (MmcOk);
614       }
615     }
616
617     return (MmcNoResponse);
618   }
619
620   MMC_RET_ERROR (res);
621 }
622
623 //
624 //
625 //
626 DSTATUS diskInitialize (U8 drv __attribute__ ((unused)))
627 {
628   mmcDskStatus.BlockNumb = mmcDskStatus.BlockSize = mmcLastError = 0;
629
630   //
631   //  Init SPI
632   //
633   spiInit ();
634
635   //
636   //  Media Init
637   //
638   switch (mmcInitMedia ())
639   {
640     case MmcOk :
641       {
642         mmcCSDImplement ();
643         mmcDskStatus.DiskStatus = DiskCommandPass;
644         mmcDskStatus.MediaChanged = TRUE;
645         Stat = 0;
646         if (mmcDskStatus.WriteProtect) 
647           Stat |= STA_PROTECT;
648       }
649       break;
650
651     case MmcCardError :
652     case MmcDataError :
653       {
654         mmcDskStatus.DiskStatus = DiskNotReady;
655         Stat = STA_NOINIT;
656         if (mmcDskStatus.WriteProtect) 
657           Stat |= STA_PROTECT;
658       }
659       break;
660
661     default:
662       {
663         mmcDskStatus.DiskStatus = DiskNotPresent;
664         Stat = STA_NODISK;
665       }
666       break;
667   }
668
669   return Stat;
670 }
671
672 //
673 //
674 //
675 DSTATUS diskShutdown (void)
676 {
677   Stat |= STA_NOINIT;
678
679   return Stat;
680 }
681
682 //
683 //
684 //
685 DSTATUS diskStatus (U8 drv __attribute__ ((unused)))
686 {
687   return Stat;
688 }
689
690 //
691 //
692 //
693 DRESULT diskRead (U8 disk __attribute__ ((unused)), U8 *buff, U32 sector, U8 count)
694 {
695   U32 res;
696
697   if (Stat & STA_NOINIT) 
698     return RES_NOTRDY;
699   if (!count) 
700     return RES_PARERR;
701
702   res = mmcRead (buff, sector * mmcDskStatus.BlockSize, count * mmcDskStatus.BlockSize);
703
704   if (res == MMC_OK)
705     return RES_OK;
706   else
707     return RES_ERROR; 
708 }
709
710 //
711 //
712 //
713 #if _FS_READONLY == 0
714 DRESULT diskWrite (U8 disk __attribute__ ((unused)), const U8 *buff, U32 sector, U8 count)
715 {
716   U32 res;
717
718   if (Stat & STA_NOINIT) 
719     return RES_NOTRDY;
720   if (Stat & STA_PROTECT) 
721     return RES_WRPRT;
722   if (!count) 
723     return RES_PARERR;
724
725   res = mmcWrite ((U8 *) buff, sector * mmcDskStatus.BlockSize, count * mmcDskStatus.BlockSize);
726
727   if (res == MMC_OK)
728     return RES_OK;
729   else
730     return RES_ERROR; 
731 }
732 #endif
733
734 //
735 //
736 //
737 DRESULT diskIoctl (U8 drv, U8 ctrl, void *buff)
738 {
739   DRESULT res;
740   U8 n;
741   U8 csd [16];
742   U16 csize;
743
744   if (drv) 
745     return RES_PARERR;
746   if (Stat & STA_NOINIT) 
747     return RES_NOTRDY;
748
749   res = RES_ERROR;
750
751   switch (ctrl) 
752   {
753     case GET_SECTOR_COUNT :
754       { 
755         mmcState_t jcwres; // ###
756         if ((jcwres = mmcReadCardInfo (csd, CMD9)) == MmcOk)                
757         {
758           //
759           //  SDC ver 2.00
760           //
761           if ((csd [0] >> 6) == 1) 
762           { 
763             csize = csd [9] + ((U16)csd [8] << 8) + 1;
764             *(U32 *) buff = (U32) csize << 10;
765           } 
766           //
767           //  MMC or SDC ver 1.XX
768           //
769           else 
770           {            
771             n = (csd [5] & 15) + ((csd [10] & 128) >> 7) + ((csd [9] & 3) << 1) + 2;
772             csize = (csd [8] >> 6) + ((U16) csd [7] << 2) + ((U16) (csd [6] & 3) << 10) + 1;
773             *(U32 *) buff = (U32) csize << (n - 9);
774           }
775
776           res = RES_OK;
777         }
778         // else // ###
779         // printf ("line %d: mmcReadCardInfo returned %d\n", __LINE__, jcwres); // ###
780       }
781       break;
782
783     case GET_SECTOR_SIZE :
784       {
785         *(U16 *) buff = 512;
786         res = RES_OK;
787       }
788       break;
789
790     case CTRL_SYNC :
791       {
792         if (spiWaitReady () == 0xff)
793           res = RES_OK;
794       }
795       break;
796
797     case MMC_GET_CSD :
798       {
799         if (mmcReadCardInfo (buff, CMD9) == MmcOk)
800           res = RES_OK;
801       }
802       break;
803
804     case MMC_GET_CID :
805       {
806         if (mmcReadCardInfo (buff, CMD10) == MmcOk)
807           res = RES_OK;
808       }
809       break;
810
811 # if 0
812     case CTRL_POWER:
813     case CTRL_LOCK:
814     case CTRL_EJECT:
815     case MMC_GET_OCR:     /* Receive OCR as an R3 resp (4 bytes) */
816     case ATA_GET_REV:
817     case ATA_GET_MODEL:
818     case ATA_GET_SN:
819 #endif                        
820
821     default:
822       res = RES_PARERR;
823   }
824
825   return res;
826 }
827
828 #if 0
829 static void mmcDump (U8 *buff, U32 ofs, U8 cnt)
830 {
831   U8 n;
832
833   printf ("\n\r%08X ", ofs);
834
835   for (n = 0; n < cnt; n++)
836     printf (" %02X", buff [n]);
837
838   putchar (' ');
839
840   for (n = 0; n < cnt; n++) 
841   {
842     if ((buff [n] < 0x20) || (buff [n] >= 0x7F))
843       putchar ('.');
844     else
845       putchar (buff [n]);
846   }
847 }
848 #endif
849
850 #if 0
851 typedef struct csd_11_s
852 {
853   unsigned int not_used_1          : 2;   // 0..1  [121:120]   0x44
854   unsigned int mmc_prot            : 4;   // 2..5  [125:122]
855   unsigned int csd_structure       : 2;   // 6..7  [127:126]
856   unsigned int taac                : 8;   // 0..7  [119:112]   0x26
857   unsigned int nsac                : 8;   // 0..7  [111:104]   0x00
858   unsigned int tran_speed          : 8;   // 0..7  [103:96]    0x2a
859   unsigned int ccc_hi              : 8;   // 0..7  [95:88]     0x1f
860   unsigned int read_bl_len         : 4;   // 0..3  [83:80]     0xf9
861   unsigned int ccc_lo              : 4;   // 4..7  [87:84]
862
863   unsigned int c_size_hi           : 2;   // 0..1  [73:72]     0x83
864   unsigned int not_used_2          : 2;   // 2..3  [75:74]
865   unsigned int dsr_imp             : 1;   // 4..4  [76:76]
866   unsigned int read_blk_misalign   : 1;   // 5..5  [77:77]
867   unsigned int write_blk_misalign  : 1;   // 6..6  [78:78]
868   unsigned int read_bl_partial     : 1;   // 7..7  [79:79]
869   unsigned int c_size_mid          : 8;   // 0..7  [71:64]     0xd3
870   unsigned int vdd_r_curr_max      : 3;   // 0..1  [58:56]     0xe3
871   unsigned int vdd_r_curr_min      : 3;   // 2..5  [61:59]
872   unsigned int c_size_lo           : 2;   // 6..7  [63:62]
873
874   unsigned int c_size_mult_hi      : 2;   // 0..1  [49:48]     0x91
875   unsigned int vdd_w_curr_max      : 3;   // 2..4  [52:50]
876   unsigned int vdd_w_curr_min      : 3;   // 4..7  [55:53]
877   unsigned int erase_grp_size_lo   : 2;   // 0..1  [41:40]     0x83
878   unsigned int sector_size         : 5;   // 2..6  [46:42]
879   unsigned int c_size_mult_lo      : 1;   // 7..7  [47:47]
880   unsigned int wp_grp_size         : 5;   // 0..4  [36:32]     0xff
881   unsigned int erase_grp_size_hi   : 3;   // 5..7  [39:37]
882
883   unsigned int write_bl_len_hi     : 2;   // 0..1  [25:24]     0x92
884   unsigned int r2w_factor          : 3;   // 2..4  [28:26]
885   unsigned int default_ecc         : 2;   // 5..6  [30:29]
886   unsigned int wp_grp_enable       : 1;   // 7..7  [31:31]     
887   unsigned int not_used_3          : 5;   // 0..4  [20:16]     0x40
888   unsigned int write_bl_partial    : 1;   // 5..5  [21:21]
889   unsigned int write_bl_len_lo     : 2;   // 6..7  [23:22]
890
891   unsigned int ecc                 : 2;   // 0..1  [9:8]       0x40
892   unsigned int not_used_5          : 2;   // 2..3  [11:10]
893   unsigned int tmp_write_protect   : 1;   // 4..4  [12:12]
894   unsigned int perm_write_protect  : 1;   // 5..5  [13:13]
895   unsigned int copy                : 1;   // 6..6  [14:14]
896   unsigned int not_used_4          : 1;   // 7..7  [15:15]
897
898   unsigned int notused_6           : 1;   // 0..0  [0:0]       0x67
899   unsigned int crc                 : 7;   // 1..7  [7:1]
900 }
901 __attribute__ ((packed)) csd_11_t;
902
903 static void mmcDecode (U8 *buffer)
904 {
905   csd_11_t *p = (csd_11_t *) buffer;
906
907   printf ("\n");
908   printf ("sizeof (csd_11_t)     : %lu\n",    sizeof (csd_11_t));
909   printf ("CSD structure version : 1.%d\n",   p->csd_structure);
910   printf ("MMC protocol version  : %d\n",     p->mmc_prot);
911   printf ("TAAC                  : 0x%02x\n", p->taac);
912   printf ("NSAC                  : 0x%02x\n", p->nsac);
913   printf ("TRAN_SPEED            : 0x%02x\n", p->tran_speed);
914   printf ("CCC                   : 0x%03x\n", (p->ccc_hi << 4) | p->ccc_lo);
915   printf ("READ_BL_LEN           : %d\n",     p->read_bl_len);
916   printf ("READ_BL_PARTIAL       : %d\n",     p->read_bl_partial);
917   printf ("WRITE_BLK_MISALIGN    : %d\n",     p->write_blk_misalign);
918   printf ("READ_BLK_MISALIGN     : %d\n",     p->read_blk_misalign);
919   printf ("DSR_IMP               : %d\n",     p->read_blk_misalign);
920   printf ("C_SIZE                : %d\n",     (p->c_size_hi << 10) | (p->c_size_mid << 2) | p->c_size_lo);
921   printf ("VDD_R_CURR_MIN        : %d\n",     p->vdd_r_curr_min);
922   printf ("VDD_R_CURR_MAX        : %d\n",     p->vdd_r_curr_max);
923   printf ("VDD_W_CURR_MIN        : %d\n",     p->vdd_w_curr_min);
924   printf ("VDD_W_CURR_MAX        : %d\n",     p->vdd_w_curr_max);
925   printf ("VDD_W_CURR_MAX        : %d\n",     p->vdd_w_curr_max);
926   printf ("C_SIZE_MULT           : %d\n",     (p->c_size_mult_hi << 1) | p->c_size_mult_lo);
927   printf ("SECTOR_SIZE           : %d\n",     p->sector_size);
928   printf ("ERASE_GRP_SIZE        : %d\n",     (p->erase_grp_size_hi << 2) | p->erase_grp_size_lo);
929   printf ("WP_GRP_SIZE           : %d\n",     p->wp_grp_size);
930   printf ("WP_GRP_ENABLE         : %d\n",     p->wp_grp_enable);
931   printf ("DEFAULT_ECC           : %d\n",     p->default_ecc);
932   printf ("R2W_FACTOR            : %d\n",     p->r2w_factor);
933   printf ("WRITE_BL_LEN          : %d\n",     (p->write_bl_len_hi << 2) | p->write_bl_len_lo);
934   printf ("WRITE_BL_PARTIAL      : %d\n",     p->write_bl_partial);
935   printf ("COPY                  : %d\n",     p->copy);
936   printf ("PERM_WRITE_PROTECT    : %d\n",     p->perm_write_protect);
937   printf ("TMP_WRITE_PROTECT     : %d\n",     p->tmp_write_protect);
938   printf ("ECC                   : %d\n",     p->ecc);
939   printf ("MEDIA SIZE            : %u\n",     (U32) (((p->c_size_hi << 10) | (p->c_size_mid << 2) | p->c_size_lo) + 1) *
940                                               (U32) (4 << ((p->c_size_mult_hi << 1) | p->c_size_mult_lo)) *
941                                               (U32) (1 << (p->read_bl_len)));
942 }
943 #endif
944