//******************************************************************************
// mmcdisk.c
// by Mauro Grassi
// for FatFs for the 89c51snd1c chip
// 2 September 2007
//******************************************************************************

#include "at89c51snd1c.h"
#include "diskio.h"
#include "mmc.h"

/*--------------------------------------------------------------------------

   Module Private Functions

---------------------------------------------------------------------------*/

static volatile xdata
DSTATUS Stat = STA_NOINIT;	/* Disk status */

static volatile xdata
BYTE CardType;			/* b0:MMC, b1:SDv1, b2:SDv2, b3:Block addressing */

/*--------------------------------------------------------------------------

   Public Functions

---------------------------------------------------------------------------*/
/*-----------------------------------------------------------------------*/
/* Initialize Disk Drive                                                 */
/*-----------------------------------------------------------------------*/

DSTATUS disk_initialize (
	BYTE drv		/* Physical drive number (0) */
)
{
	INT i;
	if (drv) return STA_NOINIT;			/* Supports only single drive */
  if (Stat & STA_NODISK) return Stat;	/* No card in the socket */
	i=initbus_mmc();
	if (i<0){Stat|=STA_NODISK; return Stat;}
	CardType = 1;      // for MMC
	if (i==0) {			/* Initialization succeded */
		Stat &=(~STA_NOINIT);		/* Clear STA_NOINIT */
	} else {			/* Initialization failed */
		Stat|=(STA_NODISK | STA_NOINIT);
	}
	return Stat;
}

/*-----------------------------------------------------------------------*/
/* Get Disk Status                                                       */
/*-----------------------------------------------------------------------*/

DSTATUS disk_status (
	BYTE drv			/* Drive number (0) */
)
{
	return (drv) ? STA_NODISK : Stat;
}

/*-----------------------------------------------------------------------*/
/* Read Sector(s)                                                        */
/*-----------------------------------------------------------------------*/

DRESULT disk_read (
	BYTE drv,		   	/* Physical drive nmuber (0) */
	BYTE *buff,			/* Pointer to the data buffer to store read data */
	DWORD sector,		/* Start sector number (LBA) */
	BYTE count			/* Sector count (1..255) */
)
{
  UINT i,number, error;
  UINT res;
  UINT done;
      
	if (drv || !count) return RES_PARERR;
	if (Stat & STA_NOINIT) return RES_NOTRDY;

  res=0;
	sector = sector<<9;	             // Convert to byte address
	
	// now we read a sector...
	
	error=0;
	
	//i=sendcom_mmc(7,0,MMCNORESPONSE, MMCSHORT, MMCCRC, MMCNODATA, 0);
	//if(i<0)error=1;
	
	//i=0;
  //if (error==0)i=sendcom_mmc(7, MMCRCA, MMCRESPONSE, MMCSHORT, MMCCRC, MMCNODATA,0);
                
	//if(i<0)error=2;
	//i=0;
	//if (error==0)i=sendcom_mmc(16,0x0200,MMCRESPONSE, MMCSHORT, MMCCRC, MMCNODATA, 0); // set the block length to 0x0200=512 bytes...
  //if (i<0)error=3;
	
	done=0;
  while((error==0)&&(done<count))
  {
  i=0;
	if (error==0)i=sendcom_mmc(17, sector, MMCRESPONSE, MMCSHORT, MMCCRC, MMCDATAREAD,512);       // read a single block of data
	if(i<0)error=4;
	if (error==0){
      number=i;
    for (i=0; i<number; i++){
     (*buff)=buffer[i];
     buff++;
   }
  }
  done++;
  }
  
  if(error==0)res=number; else res=0;
  if (error!=0)return RES_ERROR; else return RES_OK;
}

/*-----------------------------------------------------------------------*/
/* Write Sector(s)                                                       */
/*-----------------------------------------------------------------------*/

DRESULT disk_write (
	BYTE drv,			/* Physical drive nmuber (0) */
	const BYTE *buff,	/* Pointer to the data to be written */
	DWORD sector,		/* Start sector number (LBA) */
	BYTE count			/* Sector count (1..255) */
)
{
  INT i, error, number, res;
  
	if (drv || !count) return RES_PARERR;
	if (Stat & STA_NOINIT) return RES_NOTRDY;
	if (Stat & STA_PROTECT) return RES_WRPRT;

	sector = sector <<9;	// Convert to byte address
  res=0;
  
	if (1) {	/* Single block write */
	
  // now we write a sector
  error=0;
  
  i=0;
  if(error==0)i=sendcom_mmc(7,0,MMCNORESPONSE, MMCSHORT, MMCCRC, MMCNODATA,0);       // put into standby state again...
  if(i<0)error=5;
 
  error=0;
	if(error==0)i=sendcom_mmc(7, MMCRCA,MMCRESPONSE, MMCSHORT, MMCCRC, MMCNODATA,0);       // select the card- put into transfer state...
	
  if (i<0)error=1;
	
	i=0;
	if (error==0)i=sendcom_mmc(16, 0x0200,MMCRESPONSE, MMCSHORT, MMCCRC, MMCNODATA, 0); // set the block length to 0x0200=512 bytes...

	if (i<0)error=2;
	
	if (error==0){
	for(i=0; i<512; i++){
   buffer[i]=(*buff);
   buff++;
   }
  }
  
  i=0;
	if (error==0)i=sendcom_mmc(24, sector , MMCRESPONSE, MMCSHORT, MMCCRC, MMCDATAWRITE,512);       // write a single block of data
	
	if(i<0)error=3; else number=i;

 	if(error==0)res=number; else res=0;
 
  } else {				/* Multiple block write */
	 res=0;
	 // not currently supported...
	 
  }
	
	if (error!=0)return RES_ERROR; else return RES_OK;
}

/*-----------------------------------------------------------------------*/
/* Miscellaneous Functions                                               */
/*-----------------------------------------------------------------------*/
DRESULT disk_ioctl (
	BYTE drv,  		/* Physical drive nmuber (0) */
	BYTE ctrl,		/* Control code */
	void *buff		/* Buffer to send/receive control data */
)
{
	DRESULT res;
	BYTE n, *ptr = buff;
	WORD csize;
  BYTE* pointer;
  INT i;
  
	if (drv) return RES_PARERR;
	if (Stat & STA_NOINIT) return RES_NOTRDY;

	res = RES_ERROR;
	switch (ctrl) {

		case CTRL_SYNC :		/* Make sure that no pending write process */
			if(waitready_mmc()==0)res = RES_OK;
			break;

		case GET_SECTOR_COUNT :	/* Get number of sectors on the disk (DWORD) */
			
			pointer=getcsd_mmc();
			if (pointer!=0){
			
      	if ((csd[0] >> 6) == 1) {	/* SDC ver 2.00 */
					csize = csd[9] + ((WORD)csd[8] << 8) + 1;
					*(DWORD*)buff = (DWORD)csize << 10;
				} else {					/* SDC ver 1.XX or MMC */
					n = (csd[5] & 15) + ((csd[10] & 128) >> 7) + ((csd[9] & 3) << 1) + 2;
					csize = (csd[8] >> 6) + ((WORD)csd[7] << 2) + ((WORD)(csd[6] & 3) << 10) + 1;
					*(DWORD*)buff = (DWORD)csize << (n - 9);
				}
				res = RES_OK;
      }
			break;

		case GET_SECTOR_SIZE :	/* Get R/W sector size (WORD) */
			*(WORD*)buff = 512;
			res = RES_OK;
			break;

		case GET_BLOCK_SIZE :	/* Get erase block size in unit of sector (DWORD) */
			if (CardType & 4) {			/* SDC ver 2.00 */
        
          // not currently supported!
          
						}
				 else {					/* SDC ver 1.XX or MMC */
				
				pointer=getcsd_mmc();
				
				if (pointer!=0){				
					if (CardType & 2) {			/* SDC ver 1.XX */
						*(DWORD*)buff = (((csd[10] & 63) << 1) + ((WORD)(csd[11] & 128) >> 7) + 1) << ((csd[13] >> 6) - 1);
					} else {					/* MMC */
						*(DWORD*)buff = ((WORD)((csd[10] & 124) >> 2) + 1) * (((csd[11] & 3) << 3) + ((csd[11] & 224) >> 5) + 1);
						res = RES_OK;
					}
				}
			}
			break;

		case MMC_GET_TYPE :		/* Get card type flags (1 byte) */
			*ptr = CardType;
			res = RES_OK;
			break;

		case MMC_GET_CSD :		/* Receive CSD as a data block (16 bytes) */

      pointer=getcsd_mmc();
      if (pointer!=0){
       for (i=0; i<16; i++){
       (*ptr)=(*pointer);
       pointer++;
       ptr++;
       }
       res = RES_OK;
      }
			break;

		case MMC_GET_CID :		/* Receive CID as a data block (16 bytes) */
	    pointer=getcid_mmc();
	    if (pointer!=0){
      for (i=0; i<16; i++){
       (*ptr)=(*pointer);
       pointer++;
       ptr++;
       }
       res = RES_OK;
      }
	    break;

		case MMC_GET_OCR :		/* Receive OCR as an R3 resp (4 bytes) */
			pointer=getocr_mmc();
			if (pointer!=0){
      for (i=0; i<4; i++){
       (*ptr)=(*pointer);
       pointer++;
       ptr++;
       }
      res = RES_OK;
      }
			break;

		case MMC_GET_SDSTAT :	/* Receive SD status as a data block (64 bytes) */
			
			// not currently supported...
			break;

		default:
			res = RES_PARERR;
	}

	return res;
}

DWORD get_fattime()
{
return 0;
}
