| 1234 | kaklik | 1 | /*-----------------------------------------------------------------------*/ | 
      
        |  |  | 2 | /* MMC/SDC (in SPI mode) control module  (C)ChaN, 2006                   */ | 
      
        |  |  | 3 | /*-----------------------------------------------------------------------*/ | 
      
        |  |  | 4 | /* Only rcvr_spi(), xmit_spi(), disk_timerproc(), disk_initialize () and */ | 
      
        |  |  | 5 | /* some macros are platform dependent.                                   */ | 
      
        |  |  | 6 | /*-----------------------------------------------------------------------*/ | 
      
        |  |  | 7 |  | 
      
        |  |  | 8 |  | 
      
        |  |  | 9 | #include <avr/io.h> | 
      
        |  |  | 10 | #include "diskio.h" | 
      
        |  |  | 11 |  | 
      
        |  |  | 12 |  | 
      
        |  |  | 13 | /* Definitions for MMC/SDC command */ | 
      
        |  |  | 14 | #define CMD0	(0x40+0)	/* GO_IDLE_STATE */ | 
      
        |  |  | 15 | #define CMD1	(0x40+1)	/* SEND_OP_COND */ | 
      
        |  |  | 16 | #define CMD8	(0x40+8)	/* SEND_IF_COND */ | 
      
        |  |  | 17 | #define CMD9	(0x40+9)	/* SEND_CSD */ | 
      
        |  |  | 18 | #define CMD10	(0x40+10)	/* SEND_CID */ | 
      
        |  |  | 19 | #define CMD12	(0x40+12)	/* STOP_TRANSMISSION */ | 
      
        |  |  | 20 | #define CMD16	(0x40+16)	/* SET_BLOCKLEN */ | 
      
        |  |  | 21 | #define CMD17	(0x40+17)	/* READ_SINGLE_BLOCK */ | 
      
        |  |  | 22 | #define CMD18	(0x40+18)	/* READ_MULTIPLE_BLOCK */ | 
      
        |  |  | 23 | #define CMD23	(0x40+23)	/* SET_BLOCK_COUNT */ | 
      
        |  |  | 24 | #define CMD24	(0x40+24)	/* WRITE_BLOCK */ | 
      
        |  |  | 25 | #define CMD25	(0x40+25)	/* WRITE_MULTIPLE_BLOCK */ | 
      
        |  |  | 26 | #define CMD41	(0x40+41)	/* SEND_OP_COND (ACMD) */ | 
      
        |  |  | 27 | #define CMD55	(0x40+55)	/* APP_CMD */ | 
      
        |  |  | 28 | #define CMD58	(0x40+58)	/* READ_OCR */ | 
      
        |  |  | 29 |  | 
      
        |  |  | 30 |  | 
      
        |  |  | 31 | /* Control signals (Platform dependent) */ | 
      
        |  |  | 32 | #define SELECT()	PORTB &= ~_BV(PB2)	/* MMC CS = L */ | 
      
        |  |  | 33 | #define	DESELECT()	PORTB |= _BV(PB2)	/* MMC CS = H */ | 
      
        |  |  | 34 |  | 
      
        |  |  | 35 | #define SOCKPORT	PINB			/* Socket contact port */ | 
      
        |  |  | 36 | #define SOCKINS		0x01			/* Card detect switch (PB0) */ | 
      
        |  |  | 37 |  | 
      
        |  |  | 38 |  | 
      
        |  |  | 39 |  | 
      
        |  |  | 40 | /*-------------------------------------------------------------------------- | 
      
        |  |  | 41 |  | 
      
        |  |  | 42 |    Module Private Functions | 
      
        |  |  | 43 |  | 
      
        |  |  | 44 | ---------------------------------------------------------------------------*/ | 
      
        |  |  | 45 |  | 
      
        |  |  | 46 | static volatile | 
      
        |  |  | 47 | DSTATUS Stat = STA_NOINIT;	/* Disk status */ | 
      
        |  |  | 48 |  | 
      
        |  |  | 49 | static volatile | 
      
        |  |  | 50 | BYTE Timer1, Timer2;		/* 100Hz decrement timer */ | 
      
        |  |  | 51 |  | 
      
        |  |  | 52 | static | 
      
        |  |  | 53 | BYTE CardType;			/* b0:MMC, b1:SDC, b2:Block addressing */ | 
      
        |  |  | 54 |  | 
      
        |  |  | 55 |  | 
      
        |  |  | 56 |  | 
      
        |  |  | 57 | /*-----------------------------------------------------------------------*/ | 
      
        |  |  | 58 | /* Transmit a byte to MMC via SPI  (Platform dependent)                  */ | 
      
        |  |  | 59 | /*-----------------------------------------------------------------------*/ | 
      
        |  |  | 60 |  | 
      
        |  |  | 61 | #define xmit_spi(dat) 	SPDR=(dat); loop_until_bit_is_set(SPSR,SPIF) | 
      
        |  |  | 62 |  | 
      
        |  |  | 63 |  | 
      
        |  |  | 64 |  | 
      
        |  |  | 65 | /*-----------------------------------------------------------------------*/ | 
      
        |  |  | 66 | /* Receive a byte from MMC via SPI  (Platform dependent)                 */ | 
      
        |  |  | 67 | /*-----------------------------------------------------------------------*/ | 
      
        |  |  | 68 |  | 
      
        |  |  | 69 | static | 
      
        |  |  | 70 | BYTE rcvr_spi (void) | 
      
        |  |  | 71 | { | 
      
        |  |  | 72 | 	SPDR = 0xFF; | 
      
        |  |  | 73 | 	loop_until_bit_is_set(SPSR, SPIF); | 
      
        |  |  | 74 | 	return SPDR; | 
      
        |  |  | 75 | } | 
      
        |  |  | 76 |  | 
      
        |  |  | 77 | /* Alternative macro to receive data fast */ | 
      
        |  |  | 78 | #define rcvr_spi_m(dst)	SPDR=0xFF; loop_until_bit_is_set(SPSR,SPIF); *(dst)=SPDR | 
      
        |  |  | 79 |  | 
      
        |  |  | 80 |  | 
      
        |  |  | 81 |  | 
      
        |  |  | 82 | /*-----------------------------------------------------------------------*/ | 
      
        |  |  | 83 | /* Wait for card ready                                                   */ | 
      
        |  |  | 84 | /*-----------------------------------------------------------------------*/ | 
      
        |  |  | 85 |  | 
      
        |  |  | 86 | static | 
      
        |  |  | 87 | BYTE wait_ready (void) | 
      
        |  |  | 88 | { | 
      
        |  |  | 89 | 	BYTE res; | 
      
        |  |  | 90 |  | 
      
        |  |  | 91 |  | 
      
        |  |  | 92 | 	Timer2 = 50;	/* Wait for ready in timeout of 500ms */ | 
      
        |  |  | 93 | 	rcvr_spi(); | 
      
        |  |  | 94 | 	do | 
      
        |  |  | 95 | 		res = rcvr_spi(); | 
      
        |  |  | 96 | 	while ((res != 0xFF) && Timer2); | 
      
        |  |  | 97 |  | 
      
        |  |  | 98 | 	return res; | 
      
        |  |  | 99 | } | 
      
        |  |  | 100 |  | 
      
        |  |  | 101 |  | 
      
        |  |  | 102 |  | 
      
        |  |  | 103 | /*-----------------------------------------------------------------------*/ | 
      
        |  |  | 104 | /* Receive a data packet from MMC                                        */ | 
      
        |  |  | 105 | /*-----------------------------------------------------------------------*/ | 
      
        |  |  | 106 |  | 
      
        |  |  | 107 | static | 
      
        |  |  | 108 | BOOL rcvr_datablock ( | 
      
        |  |  | 109 | 	BYTE *buff,			/* Data buffer to store received data */ | 
      
        |  |  | 110 | 	UINT btr			/* Byte count (must be even number) */ | 
      
        |  |  | 111 | ) | 
      
        |  |  | 112 | { | 
      
        |  |  | 113 | 	BYTE token; | 
      
        |  |  | 114 |  | 
      
        |  |  | 115 |  | 
      
        |  |  | 116 | 	Timer1 = 10; | 
      
        |  |  | 117 | 	do {							/* Wait for data packet in timeout of 100ms */ | 
      
        |  |  | 118 | 		token = rcvr_spi(); | 
      
        |  |  | 119 | 	} while ((token == 0xFF) && Timer1); | 
      
        |  |  | 120 | 	if(token != 0xFE) return FALSE;	/* If not valid data token, retutn with error */ | 
      
        |  |  | 121 |  | 
      
        |  |  | 122 | 	do {							/* Receive the data block into buffer */ | 
      
        |  |  | 123 | 		rcvr_spi_m(buff++); | 
      
        |  |  | 124 | 		rcvr_spi_m(buff++); | 
      
        |  |  | 125 | 	} while (btr -= 2); | 
      
        |  |  | 126 | 	rcvr_spi();						/* Discard CRC */ | 
      
        |  |  | 127 | 	rcvr_spi(); | 
      
        |  |  | 128 |  | 
      
        |  |  | 129 | 	return TRUE;					/* Return with success */ | 
      
        |  |  | 130 | } | 
      
        |  |  | 131 |  | 
      
        |  |  | 132 |  | 
      
        |  |  | 133 |  | 
      
        |  |  | 134 | /*-----------------------------------------------------------------------*/ | 
      
        |  |  | 135 | /* Send a data packet to MMC                                             */ | 
      
        |  |  | 136 | /*-----------------------------------------------------------------------*/ | 
      
        |  |  | 137 |  | 
      
        |  |  | 138 | #if _READONLY == 0 | 
      
        |  |  | 139 | static | 
      
        |  |  | 140 | BOOL xmit_datablock ( | 
      
        |  |  | 141 | 	const BYTE *buff,	/* 512 byte data block to be transmitted */ | 
      
        |  |  | 142 | 	BYTE token			/* Data/Stop token */ | 
      
        |  |  | 143 | ) | 
      
        |  |  | 144 | { | 
      
        |  |  | 145 | 	BYTE resp, wc; | 
      
        |  |  | 146 |  | 
      
        |  |  | 147 |  | 
      
        |  |  | 148 | 	if (wait_ready() != 0xFF) return FALSE; | 
      
        |  |  | 149 |  | 
      
        |  |  | 150 | 	xmit_spi(token);					/* Xmit data token */ | 
      
        |  |  | 151 | 	if (token != 0xFD) {	/* Is data token */ | 
      
        |  |  | 152 | 		wc = 0; | 
      
        |  |  | 153 | 		do {							/* Xmit the 512 byte data block to MMC */ | 
      
        |  |  | 154 | 			xmit_spi(*buff++); | 
      
        |  |  | 155 | 			xmit_spi(*buff++); | 
      
        |  |  | 156 | 		} while (--wc); | 
      
        |  |  | 157 | 		xmit_spi(0xFF);					/* CRC (Dummy) */ | 
      
        |  |  | 158 | 		xmit_spi(0xFF); | 
      
        |  |  | 159 | 		resp = rcvr_spi();				/* Reveive data response */ | 
      
        |  |  | 160 | 		if ((resp & 0x1F) != 0x05)		/* If not accepted, return with error */ | 
      
        |  |  | 161 | 			return FALSE; | 
      
        |  |  | 162 | 	} | 
      
        |  |  | 163 |  | 
      
        |  |  | 164 | 	return TRUE; | 
      
        |  |  | 165 | } | 
      
        |  |  | 166 | #endif /* _READONLY */ | 
      
        |  |  | 167 |  | 
      
        |  |  | 168 |  | 
      
        |  |  | 169 |  | 
      
        |  |  | 170 | /*-----------------------------------------------------------------------*/ | 
      
        |  |  | 171 | /* Send a command packet to MMC                                          */ | 
      
        |  |  | 172 | /*-----------------------------------------------------------------------*/ | 
      
        |  |  | 173 |  | 
      
        |  |  | 174 | static | 
      
        |  |  | 175 | BYTE send_cmd ( | 
      
        |  |  | 176 | 	BYTE cmd,		/* Command byte */ | 
      
        |  |  | 177 | 	DWORD arg		/* Argument */ | 
      
        |  |  | 178 | ) | 
      
        |  |  | 179 | { | 
      
        |  |  | 180 | 	BYTE n, res; | 
      
        |  |  | 181 |  | 
      
        |  |  | 182 |  | 
      
        |  |  | 183 | 	if (wait_ready() != 0xFF) return 0xFF; | 
      
        |  |  | 184 |  | 
      
        |  |  | 185 | 	/* Send command packet */ | 
      
        |  |  | 186 | 	xmit_spi(cmd);						/* Command */ | 
      
        |  |  | 187 | 	xmit_spi((BYTE)(arg >> 24));		/* Argument[31..24] */ | 
      
        |  |  | 188 | 	xmit_spi((BYTE)(arg >> 16));		/* Argument[23..16] */ | 
      
        |  |  | 189 | 	xmit_spi((BYTE)(arg >> 8));			/* Argument[15..8] */ | 
      
        |  |  | 190 | 	xmit_spi((BYTE)arg);				/* Argument[7..0] */ | 
      
        |  |  | 191 | 	n = 0; | 
      
        |  |  | 192 | 	if (cmd == CMD0) n = 0x95;			/* CRC for CMD0(0) */ | 
      
        |  |  | 193 | 	if (cmd == CMD8) n = 0x87;			/* CRC for CMD8(0x1AA) */ | 
      
        |  |  | 194 | 	xmit_spi(n); | 
      
        |  |  | 195 |  | 
      
        |  |  | 196 | 	/* Receive command response */ | 
      
        |  |  | 197 | 	if (cmd == CMD12) rcvr_spi();		/* Skip a stuff byte when stop reading */ | 
      
        |  |  | 198 | 	n = 10;								/* Wait for a valid response in timeout of 10 attempts */ | 
      
        |  |  | 199 | 	do | 
      
        |  |  | 200 | 		res = rcvr_spi(); | 
      
        |  |  | 201 | 	while ((res & 0x80) && --n); | 
      
        |  |  | 202 |  | 
      
        |  |  | 203 | 	return res;			/* Return with the response value */ | 
      
        |  |  | 204 | } | 
      
        |  |  | 205 |  | 
      
        |  |  | 206 |  | 
      
        |  |  | 207 |  | 
      
        |  |  | 208 |  | 
      
        |  |  | 209 | /*-------------------------------------------------------------------------- | 
      
        |  |  | 210 |  | 
      
        |  |  | 211 |    Public Functions | 
      
        |  |  | 212 |  | 
      
        |  |  | 213 | ---------------------------------------------------------------------------*/ | 
      
        |  |  | 214 |  | 
      
        |  |  | 215 |  | 
      
        |  |  | 216 | /*-----------------------------------------------------------------------*/ | 
      
        |  |  | 217 | /* Initialize Disk Drive                                                 */ | 
      
        |  |  | 218 | /*-----------------------------------------------------------------------*/ | 
      
        |  |  | 219 |  | 
      
        |  |  | 220 | DSTATUS disk_initialize ( | 
      
        |  |  | 221 | 	BYTE drv		/* Physical drive nmuber (0) */ | 
      
        |  |  | 222 | ) | 
      
        |  |  | 223 | { | 
      
        |  |  | 224 | 	BYTE n, ty, ocr[4]; | 
      
        |  |  | 225 |  | 
      
        |  |  | 226 |  | 
      
        |  |  | 227 | 	if (drv) return STA_NOINIT;			/* Supports only single drive */ | 
      
        |  |  | 228 | 	if (Stat & STA_NODISK) return Stat;	/* No card in the socket */ | 
      
        |  |  | 229 |  | 
      
        |  |  | 230 | 	for (n = 10; n; n--) rcvr_spi();	/* 80 dummy clocks */ | 
      
        |  |  | 231 |  | 
      
        |  |  | 232 | 	SELECT();				/* CS = L */ | 
      
        |  |  | 233 | 	ty = 0; | 
      
        |  |  | 234 | 	if (send_cmd(CMD0, 0) == 1) {			/* Enter Idle state */ | 
      
        |  |  | 235 | 		Timer1 = 100;						/* Initialization timeout of 1000 msec */ | 
      
        |  |  | 236 | 		if (send_cmd(CMD8, 0x1AA) == 1) {	/* SDC Ver2+ */ | 
      
        |  |  | 237 | 			for (n = 0; n < 4; n++) ocr[n] = rcvr_spi(); | 
      
        |  |  | 238 | 			if (ocr[2] == 0x01 && ocr[3] == 0xAA) {	/* The card can work at vdd range of 2.7-3.6V */ | 
      
        |  |  | 239 | 				do { | 
      
        |  |  | 240 | 					if (send_cmd(CMD55, 0) <= 1 && send_cmd(CMD41, 1UL << 30) == 0)	break;	/* ACMD41 with HCS bit */ | 
      
        |  |  | 241 | 				} while (Timer1); | 
      
        |  |  | 242 | 				if (Timer1 && send_cmd(CMD58, 0) == 0) {	/* Check CCS bit */ | 
      
        |  |  | 243 | 					for (n = 0; n < 4; n++) ocr[n] = rcvr_spi(); | 
      
        |  |  | 244 | 					ty = (ocr[0] & 0x40) ? 6 : 2; | 
      
        |  |  | 245 | 				} | 
      
        |  |  | 246 | 			} | 
      
        |  |  | 247 | 		} else {							/* SDC Ver1 or MMC */ | 
      
        |  |  | 248 | 			ty = (send_cmd(CMD55, 0) <= 1 && send_cmd(CMD41, 0) <= 1) ? 2 : 1;	/* SDC : MMC */ | 
      
        |  |  | 249 | 			do { | 
      
        |  |  | 250 | 				if (ty == 2) { | 
      
        |  |  | 251 | 					if (send_cmd(CMD55, 0) <= 1 && send_cmd(CMD41, 0) == 0) break;	/* ACMD41 */ | 
      
        |  |  | 252 | 				} else { | 
      
        |  |  | 253 | 					if (send_cmd(CMD1, 0) == 0) break;								/* CMD1 */ | 
      
        |  |  | 254 | 				} | 
      
        |  |  | 255 | 			} while (Timer1); | 
      
        |  |  | 256 | 			if (!Timer1 || send_cmd(CMD16, 512) != 0)	/* Select R/W block length */ | 
      
        |  |  | 257 | 				ty = 0; | 
      
        |  |  | 258 | 		} | 
      
        |  |  | 259 | 	} | 
      
        |  |  | 260 | 	CardType = ty; | 
      
        |  |  | 261 | 	DESELECT();			/* CS = H */ | 
      
        |  |  | 262 | 	rcvr_spi();			/* Idle (Release DO) */ | 
      
        |  |  | 263 |  | 
      
        |  |  | 264 | 	if (ty) {			/* Initialization succeded */ | 
      
        |  |  | 265 | 		Stat &= ~STA_NOINIT;		/* Clear STA_NOINIT */ | 
      
        |  |  | 266 | 	} else {			/* Initialization failed */ | 
      
        |  |  | 267 | 		Stat |=  STA_NOINIT;		/* Set STA_NOINIT */ | 
      
        |  |  | 268 | 	} | 
      
        |  |  | 269 |  | 
      
        |  |  | 270 | 	return Stat; | 
      
        |  |  | 271 | } | 
      
        |  |  | 272 |  | 
      
        |  |  | 273 |  | 
      
        |  |  | 274 |  | 
      
        |  |  | 275 | /*-----------------------------------------------------------------------*/ | 
      
        |  |  | 276 | /* Get Disk Status                                                       */ | 
      
        |  |  | 277 | /*-----------------------------------------------------------------------*/ | 
      
        |  |  | 278 |  | 
      
        |  |  | 279 | DSTATUS disk_status ( | 
      
        |  |  | 280 | 	BYTE drv		/* Physical drive nmuber (0) */ | 
      
        |  |  | 281 | ) | 
      
        |  |  | 282 | { | 
      
        |  |  | 283 | 	if (drv) return STA_NOINIT;		/* Supports only single drive */ | 
      
        |  |  | 284 | 	return Stat; | 
      
        |  |  | 285 | } | 
      
        |  |  | 286 |  | 
      
        |  |  | 287 |  | 
      
        |  |  | 288 |  | 
      
        |  |  | 289 | /*-----------------------------------------------------------------------*/ | 
      
        |  |  | 290 | /* Read Sector(s)                                                        */ | 
      
        |  |  | 291 | /*-----------------------------------------------------------------------*/ | 
      
        |  |  | 292 |  | 
      
        |  |  | 293 | DRESULT disk_read ( | 
      
        |  |  | 294 | 	BYTE drv,			/* Physical drive nmuber (0) */ | 
      
        |  |  | 295 | 	BYTE *buff,			/* Pointer to the data buffer to store read data */ | 
      
        |  |  | 296 | 	DWORD sector,		/* Start sector number (LBA) */ | 
      
        |  |  | 297 | 	BYTE count			/* Sector count (1..255) */ | 
      
        |  |  | 298 | ) | 
      
        |  |  | 299 | { | 
      
        |  |  | 300 | 	if (drv || !count) return RES_PARERR; | 
      
        |  |  | 301 | 	if (Stat & STA_NOINIT) return RES_NOTRDY; | 
      
        |  |  | 302 |  | 
      
        |  |  | 303 | 	if (!(CardType & 4)) sector *= 512;	/* Convert to byte address if needed */ | 
      
        |  |  | 304 |  | 
      
        |  |  | 305 | 	SELECT();			/* CS = L */ | 
      
        |  |  | 306 |  | 
      
        |  |  | 307 | 	if (count == 1) {	/* Single block read */ | 
      
        |  |  | 308 | 		if ((send_cmd(CMD17, sector) == 0)	/* READ_SINGLE_BLOCK */ | 
      
        |  |  | 309 | 			&& rcvr_datablock(buff, 512)) | 
      
        |  |  | 310 | 			count = 0; | 
      
        |  |  | 311 | 	} | 
      
        |  |  | 312 | 	else {				/* Multiple block read */ | 
      
        |  |  | 313 | 		if (send_cmd(CMD18, sector) == 0) {	/* READ_MULTIPLE_BLOCK */ | 
      
        |  |  | 314 | 			do { | 
      
        |  |  | 315 | 				if (!rcvr_datablock(buff, 512)) break; | 
      
        |  |  | 316 | 				buff += 512; | 
      
        |  |  | 317 | 			} while (--count); | 
      
        |  |  | 318 | 			send_cmd(CMD12, 0);				/* STOP_TRANSMISSION */ | 
      
        |  |  | 319 | 		} | 
      
        |  |  | 320 | 	} | 
      
        |  |  | 321 |  | 
      
        |  |  | 322 | 	DESELECT();			/* CS = H */ | 
      
        |  |  | 323 | 	rcvr_spi();			/* Idle (Release DO) */ | 
      
        |  |  | 324 |  | 
      
        |  |  | 325 | 	return count ? RES_ERROR : RES_OK; | 
      
        |  |  | 326 | } | 
      
        |  |  | 327 |  | 
      
        |  |  | 328 |  | 
      
        |  |  | 329 |  | 
      
        |  |  | 330 | /*-----------------------------------------------------------------------*/ | 
      
        |  |  | 331 | /* Write Sector(s)                                                       */ | 
      
        |  |  | 332 | /*-----------------------------------------------------------------------*/ | 
      
        |  |  | 333 |  | 
      
        |  |  | 334 | #if _READONLY == 0 | 
      
        |  |  | 335 | DRESULT disk_write ( | 
      
        |  |  | 336 | 	BYTE drv,			/* Physical drive nmuber (0) */ | 
      
        |  |  | 337 | 	const BYTE *buff,	/* Pointer to the data to be written */ | 
      
        |  |  | 338 | 	DWORD sector,		/* Start sector number (LBA) */ | 
      
        |  |  | 339 | 	BYTE count			/* Sector count (1..255) */ | 
      
        |  |  | 340 | ) | 
      
        |  |  | 341 | { | 
      
        |  |  | 342 | 	if (drv || !count) return RES_PARERR; | 
      
        |  |  | 343 | 	if (Stat & STA_NOINIT) return RES_NOTRDY; | 
      
        |  |  | 344 | 	if (Stat & STA_PROTECT) return RES_WRPRT; | 
      
        |  |  | 345 |  | 
      
        |  |  | 346 | 	if (!(CardType & 4)) sector *= 512;	/* Convert to byte address if needed */ | 
      
        |  |  | 347 |  | 
      
        |  |  | 348 | 	SELECT();			/* CS = L */ | 
      
        |  |  | 349 |  | 
      
        |  |  | 350 | 	if (count == 1) {	/* Single block write */ | 
      
        |  |  | 351 | 		if ((send_cmd(CMD24, sector) == 0)	/* WRITE_BLOCK */ | 
      
        |  |  | 352 | 			&& xmit_datablock(buff, 0xFE)) | 
      
        |  |  | 353 | 			count = 0; | 
      
        |  |  | 354 | 	} | 
      
        |  |  | 355 | 	else {				/* Multiple block write */ | 
      
        |  |  | 356 | 		if (CardType & 2) { | 
      
        |  |  | 357 | 			send_cmd(CMD55, 0); send_cmd(CMD23, count);	/* ACMD23 */ | 
      
        |  |  | 358 | 		} | 
      
        |  |  | 359 | 		if (send_cmd(CMD25, sector) == 0) {	/* WRITE_MULTIPLE_BLOCK */ | 
      
        |  |  | 360 | 			do { | 
      
        |  |  | 361 | 				if (!xmit_datablock(buff, 0xFC)) break; | 
      
        |  |  | 362 | 				buff += 512; | 
      
        |  |  | 363 | 			} while (--count); | 
      
        |  |  | 364 | 			if (!xmit_datablock(0, 0xFD))	/* STOP_TRAN token */ | 
      
        |  |  | 365 | 				count = 1; | 
      
        |  |  | 366 | 		} | 
      
        |  |  | 367 | 	} | 
      
        |  |  | 368 |  | 
      
        |  |  | 369 | 	DESELECT();			/* CS = H */ | 
      
        |  |  | 370 | 	rcvr_spi();			/* Idle (Release DO) */ | 
      
        |  |  | 371 |  | 
      
        |  |  | 372 | 	return count ? RES_ERROR : RES_OK; | 
      
        |  |  | 373 | } | 
      
        |  |  | 374 | #endif /* _READONLY */ | 
      
        |  |  | 375 |  | 
      
        |  |  | 376 |  | 
      
        |  |  | 377 |  | 
      
        |  |  | 378 | /*-----------------------------------------------------------------------*/ | 
      
        |  |  | 379 | /* Miscellaneous Functions                                               */ | 
      
        |  |  | 380 | /*-----------------------------------------------------------------------*/ | 
      
        |  |  | 381 |  | 
      
        |  |  | 382 | DRESULT disk_ioctl ( | 
      
        |  |  | 383 | 	BYTE drv,		/* Physical drive nmuber (0) */ | 
      
        |  |  | 384 | 	BYTE ctrl,		/* Control code */ | 
      
        |  |  | 385 | 	void *buff		/* Buffer to send/receive data block */ | 
      
        |  |  | 386 | ) | 
      
        |  |  | 387 | { | 
      
        |  |  | 388 | 	DRESULT res; | 
      
        |  |  | 389 | 	BYTE n, csd[16], *ptr = buff; | 
      
        |  |  | 390 | 	WORD csize; | 
      
        |  |  | 391 |  | 
      
        |  |  | 392 |  | 
      
        |  |  | 393 | 	if (drv) return RES_PARERR; | 
      
        |  |  | 394 |  | 
      
        |  |  | 395 | 	SELECT();		/* CS = L */ | 
      
        |  |  | 396 |  | 
      
        |  |  | 397 | 	res = RES_ERROR; | 
      
        |  |  | 398 | 	switch (ctrl) { | 
      
        |  |  | 399 | 		case GET_SECTOR_COUNT :	/* Get number of sectors on the disk (DWORD) */ | 
      
        |  |  | 400 | 			if ((send_cmd(CMD9, 0) == 0) && rcvr_datablock(csd, 16)) { | 
      
        |  |  | 401 | 				if ((csd[0] >> 6) == 1) {	/* SDC ver 2.00 */ | 
      
        |  |  | 402 | 					csize = csd[9] + ((WORD)csd[8] << 8) + 1; | 
      
        |  |  | 403 | 					*(DWORD*)buff = (DWORD)csize << 10; | 
      
        |  |  | 404 | 				} else {					/* MMC or SDC ver 1.XX */ | 
      
        |  |  | 405 | 					n = (csd[5] & 15) + ((csd[10] & 128) >> 7) + ((csd[9] & 3) << 1) + 2; | 
      
        |  |  | 406 | 					csize = (csd[8] >> 6) + ((WORD)csd[7] << 2) + ((WORD)(csd[6] & 3) << 10) + 1; | 
      
        |  |  | 407 | 					*(DWORD*)buff = (DWORD)csize << (n - 9); | 
      
        |  |  | 408 | 				} | 
      
        |  |  | 409 | 				res = RES_OK; | 
      
        |  |  | 410 | 			} | 
      
        |  |  | 411 | 			break; | 
      
        |  |  | 412 |  | 
      
        |  |  | 413 | 		case GET_SECTOR_SIZE :	/* Get sectors on the disk (WORD) */ | 
      
        |  |  | 414 | 			*(WORD*)buff = 512; | 
      
        |  |  | 415 | 			res = RES_OK; | 
      
        |  |  | 416 | 			break; | 
      
        |  |  | 417 |  | 
      
        |  |  | 418 | 		case CTRL_SYNC :	/* Make sure that data has been written */ | 
      
        |  |  | 419 | 			if (wait_ready() == 0xFF) | 
      
        |  |  | 420 | 				res = RES_OK; | 
      
        |  |  | 421 | 			break; | 
      
        |  |  | 422 |  | 
      
        |  |  | 423 | 		case MMC_GET_CSD :	/* Receive CSD as a data block (16 bytes) */ | 
      
        |  |  | 424 | 			if (Stat & STA_NOINIT) return RES_NOTRDY; | 
      
        |  |  | 425 | 			if ((send_cmd(CMD9, 0) == 0)	/* READ_CSD */ | 
      
        |  |  | 426 | 				&& rcvr_datablock(ptr, 16)) | 
      
        |  |  | 427 | 				res = RES_OK; | 
      
        |  |  | 428 | 			break; | 
      
        |  |  | 429 |  | 
      
        |  |  | 430 | 		case MMC_GET_CID :	/* Receive CID as a data block (16 bytes) */ | 
      
        |  |  | 431 | 			if (Stat & STA_NOINIT) return RES_NOTRDY; | 
      
        |  |  | 432 | 			if ((send_cmd(CMD10, 0) == 0)	/* READ_CID */ | 
      
        |  |  | 433 | 				&& rcvr_datablock(ptr, 16)) | 
      
        |  |  | 434 | 				res = RES_OK; | 
      
        |  |  | 435 | 			break; | 
      
        |  |  | 436 |  | 
      
        |  |  | 437 | 		case MMC_GET_OCR :	/* Receive OCR as an R3 resp (4 bytes) */ | 
      
        |  |  | 438 | 			if (Stat & STA_NOINIT) return RES_NOTRDY; | 
      
        |  |  | 439 | 			if (send_cmd(CMD58, 0) == 0) {	/* READ_OCR */ | 
      
        |  |  | 440 | 				for (n = 0; n < 4; n++) | 
      
        |  |  | 441 | 					*ptr++ = rcvr_spi(); | 
      
        |  |  | 442 | 				res = RES_OK; | 
      
        |  |  | 443 | 			} | 
      
        |  |  | 444 | 			break; | 
      
        |  |  | 445 |  | 
      
        |  |  | 446 | 		default: | 
      
        |  |  | 447 | 			res = RES_PARERR; | 
      
        |  |  | 448 | 	} | 
      
        |  |  | 449 |  | 
      
        |  |  | 450 | 	DESELECT();			/* CS = H */ | 
      
        |  |  | 451 | 	rcvr_spi();			/* Idle (Release DO) */ | 
      
        |  |  | 452 |  | 
      
        |  |  | 453 | 	return res; | 
      
        |  |  | 454 | } | 
      
        |  |  | 455 |  | 
      
        |  |  | 456 |  | 
      
        |  |  | 457 |  | 
      
        |  |  | 458 | /*---------------------------------------*/ | 
      
        |  |  | 459 | /* Device timer interrupt procedure      */ | 
      
        |  |  | 460 | /* This must be called in period of 10ms */ | 
      
        |  |  | 461 | /* (Platform dependent)                  */ | 
      
        |  |  | 462 |  | 
      
        |  |  | 463 | void disk_timerproc (void) | 
      
        |  |  | 464 | { | 
      
        |  |  | 465 | 	static BYTE pv; | 
      
        |  |  | 466 | 	BYTE n, s; | 
      
        |  |  | 467 |  | 
      
        |  |  | 468 |  | 
      
        |  |  | 469 | 	n = Timer1;						/* 100Hz decrement timer */ | 
      
        |  |  | 470 | 	if (n) Timer1 = --n; | 
      
        |  |  | 471 | 	n = Timer2; | 
      
        |  |  | 472 | 	if (n) Timer2 = --n; | 
      
        |  |  | 473 |  | 
      
        |  |  | 474 | 	n = pv; | 
      
        |  |  | 475 | 	pv = SOCKPORT & (SOCKINS);		/* Sample socket switch */ | 
      
        |  |  | 476 |  | 
      
        |  |  | 477 | 	if (n == pv) {					/* Have contacts stabled? */ | 
      
        |  |  | 478 | 		s = Stat; | 
      
        |  |  | 479 | 		if (pv & SOCKINS)			/* INS = H (Socket empty) */ | 
      
        |  |  | 480 | 			s |= (STA_NODISK | STA_NOINIT); | 
      
        |  |  | 481 | 		else						/* INS = L (Card inserted) */ | 
      
        |  |  | 482 | 			s &= ~STA_NODISK; | 
      
        |  |  | 483 |  | 
      
        |  |  | 484 | 		Stat = s; | 
      
        |  |  | 485 | 	} | 
      
        |  |  | 486 | } | 
      
        |  |  | 487 |  |