Mercurial > templog
comparison mmc.c @ 309:49e83333e546
Add FatFS
author | Matt Johnston <matt@ucc.asn.au> |
---|---|
date | Tue, 08 May 2012 22:51:38 +0800 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
308:e36ee3e156c1 | 309:49e83333e546 |
---|---|
1 /*-----------------------------------------------------------------------*/ | |
2 /* MMCv3/SDv1/SDv2 (in SPI mode) control module (C)ChaN, 2010 */ | |
3 /*-----------------------------------------------------------------------*/ | |
4 /* Only rcvr_spi(), xmit_spi(), disk_timerproc() and some macros */ | |
5 /* are platform dependent. */ | |
6 /*-----------------------------------------------------------------------*/ | |
7 | |
8 | |
9 #include <avr/io.h> | |
10 #include "diskio.h" | |
11 | |
12 | |
13 /*-------------------------------------------------------------------------- | |
14 | |
15 Module Private Functions | |
16 | |
17 ---------------------------------------------------------------------------*/ | |
18 | |
19 /* Port Controls (Platform dependent) */ | |
20 #define CS_LOW() PORTB &= ~1 /* MMC CS = L */ | |
21 #define CS_HIGH() PORTB |= 1 /* MMC CS = H */ | |
22 #define SOCKWP (PINB & 0x20) /* Write protected. yes:true, no:false, default:false */ | |
23 #define SOCKINS (!(PINB & 0x10)) /* Card detected. yes:true, no:false, default:true */ | |
24 | |
25 #define FCLK_SLOW() SPCR = 0x52 /* Set slow clock (100k-400k) */ | |
26 #define FCLK_FAST() SPCR = 0x50 /* Set fast clock (depends on the CSD) */ | |
27 | |
28 | |
29 /* Definitions for MMC/SDC command */ | |
30 #define CMD0 (0) /* GO_IDLE_STATE */ | |
31 #define CMD1 (1) /* SEND_OP_COND (MMC) */ | |
32 #define ACMD41 (0x80+41) /* SEND_OP_COND (SDC) */ | |
33 #define CMD8 (8) /* SEND_IF_COND */ | |
34 #define CMD9 (9) /* SEND_CSD */ | |
35 #define CMD10 (10) /* SEND_CID */ | |
36 #define CMD12 (12) /* STOP_TRANSMISSION */ | |
37 #define ACMD13 (0x80+13) /* SD_STATUS (SDC) */ | |
38 #define CMD16 (16) /* SET_BLOCKLEN */ | |
39 #define CMD17 (17) /* READ_SINGLE_BLOCK */ | |
40 #define CMD18 (18) /* READ_MULTIPLE_BLOCK */ | |
41 #define CMD23 (23) /* SET_BLOCK_COUNT (MMC) */ | |
42 #define ACMD23 (0x80+23) /* SET_WR_BLK_ERASE_COUNT (SDC) */ | |
43 #define CMD24 (24) /* WRITE_BLOCK */ | |
44 #define CMD25 (25) /* WRITE_MULTIPLE_BLOCK */ | |
45 #define CMD55 (55) /* APP_CMD */ | |
46 #define CMD58 (58) /* READ_OCR */ | |
47 | |
48 /* Card type flags (CardType) */ | |
49 #define CT_MMC 0x01 /* MMC ver 3 */ | |
50 #define CT_SD1 0x02 /* SD ver 1 */ | |
51 #define CT_SD2 0x04 /* SD ver 2 */ | |
52 #define CT_SDC (CT_SD1|CT_SD2) /* SD */ | |
53 #define CT_BLOCK 0x08 /* Block addressing */ | |
54 | |
55 | |
56 static volatile | |
57 DSTATUS Stat = STA_NOINIT; /* Disk status */ | |
58 | |
59 static volatile | |
60 BYTE Timer1, Timer2; /* 100Hz decrement timer */ | |
61 | |
62 static | |
63 BYTE CardType; /* Card type flags */ | |
64 | |
65 | |
66 /*-----------------------------------------------------------------------*/ | |
67 /* Transmit a byte to MMC via SPI (Platform dependent) */ | |
68 /*-----------------------------------------------------------------------*/ | |
69 | |
70 #define xmit_spi(dat) SPDR=(dat); loop_until_bit_is_set(SPSR,SPIF) | |
71 | |
72 | |
73 | |
74 /*-----------------------------------------------------------------------*/ | |
75 /* Receive a byte from MMC via SPI (Platform dependent) */ | |
76 /*-----------------------------------------------------------------------*/ | |
77 | |
78 static | |
79 BYTE rcvr_spi (void) | |
80 { | |
81 SPDR = 0xFF; | |
82 loop_until_bit_is_set(SPSR, SPIF); | |
83 return SPDR; | |
84 } | |
85 | |
86 /* Alternative macro to receive data fast */ | |
87 #define rcvr_spi_m(dst) SPDR=0xFF; loop_until_bit_is_set(SPSR,SPIF); *(dst)=SPDR | |
88 | |
89 | |
90 | |
91 /*-----------------------------------------------------------------------*/ | |
92 /* Wait for card ready */ | |
93 /*-----------------------------------------------------------------------*/ | |
94 | |
95 static | |
96 int wait_ready (void) /* 1:OK, 0:Timeout */ | |
97 { | |
98 BYTE d; | |
99 | |
100 | |
101 Timer2 = 50; /* Wait for ready in timeout of 500ms */ | |
102 do | |
103 d = rcvr_spi(); | |
104 while (d != 0xFF && Timer2); | |
105 | |
106 return (d == 0xFF) ? 1 : 0; | |
107 } | |
108 | |
109 | |
110 | |
111 /*-----------------------------------------------------------------------*/ | |
112 /* Deselect the card and release SPI bus */ | |
113 /*-----------------------------------------------------------------------*/ | |
114 | |
115 static | |
116 void deselect (void) | |
117 { | |
118 CS_HIGH(); | |
119 rcvr_spi(); /* Dummy clock (force DO hi-z for multiple slave SPI) */ | |
120 } | |
121 | |
122 | |
123 | |
124 /*-----------------------------------------------------------------------*/ | |
125 /* Select the card and wait for ready */ | |
126 /*-----------------------------------------------------------------------*/ | |
127 | |
128 static | |
129 int select (void) /* 1:Successful, 0:Timeout */ | |
130 { | |
131 CS_LOW(); | |
132 rcvr_spi(); /* Dummy clock (force DO enabled) */ | |
133 | |
134 if (wait_ready()) return 1; /* OK */ | |
135 deselect(); | |
136 return 0; /* Timeout */ | |
137 } | |
138 | |
139 | |
140 | |
141 /*-----------------------------------------------------------------------*/ | |
142 /* Power Control (Platform dependent) */ | |
143 /*-----------------------------------------------------------------------*/ | |
144 /* When the target system does not support socket power control, there */ | |
145 /* is nothing to do in these functions and chk_power always returns 1. */ | |
146 | |
147 static | |
148 int power_status(void) /* Socket power state: 0=off, 1=on */ | |
149 { | |
150 return 0; | |
151 // matt | |
152 //return (PORTE & 0x80) ? 0 : 1; | |
153 } | |
154 | |
155 | |
156 static | |
157 void power_on (void) | |
158 { | |
159 // matt | |
160 #if 0 | |
161 PORTE &= ~0x80; /* Socket power on */ | |
162 for (Timer1 = 2; Timer1; ); /* Wait for 20ms */ | |
163 PORTB = 0b10110101; /* Enable drivers */ | |
164 DDRB = 0b11000111; | |
165 #endif | |
166 | |
167 SPCR = 0x52; /* Enable SPI function in mode 0 */ | |
168 SPSR = 0x01; /* SPI 2x mode */ | |
169 } | |
170 | |
171 | |
172 static | |
173 void power_off (void) | |
174 { | |
175 SPCR = 0; /* Disable SPI function */ | |
176 DDRB = 0b11000000; /* Disable drivers */ | |
177 PORTB = 0b10110000; | |
178 | |
179 // matt | |
180 #if 0 | |
181 PORTE |= 0x80; /* Socket power off */ | |
182 #endif | |
183 Stat |= STA_NOINIT; | |
184 } | |
185 | |
186 | |
187 | |
188 /*-----------------------------------------------------------------------*/ | |
189 /* Receive a data packet from MMC */ | |
190 /*-----------------------------------------------------------------------*/ | |
191 | |
192 static | |
193 int rcvr_datablock ( | |
194 BYTE *buff, /* Data buffer to store received data */ | |
195 UINT btr /* Byte count (must be multiple of 4) */ | |
196 ) | |
197 { | |
198 BYTE token; | |
199 | |
200 | |
201 Timer1 = 20; | |
202 do { /* Wait for data packet in timeout of 200ms */ | |
203 token = rcvr_spi(); | |
204 } while ((token == 0xFF) && Timer1); | |
205 if(token != 0xFE) return 0; /* If not valid data token, retutn with error */ | |
206 | |
207 do { /* Receive the data block into buffer */ | |
208 rcvr_spi_m(buff++); | |
209 rcvr_spi_m(buff++); | |
210 rcvr_spi_m(buff++); | |
211 rcvr_spi_m(buff++); | |
212 } while (btr -= 4); | |
213 rcvr_spi(); /* Discard CRC */ | |
214 rcvr_spi(); | |
215 | |
216 return 1; /* Return with success */ | |
217 } | |
218 | |
219 | |
220 | |
221 /*-----------------------------------------------------------------------*/ | |
222 /* Send a data packet to MMC */ | |
223 /*-----------------------------------------------------------------------*/ | |
224 | |
225 static | |
226 int xmit_datablock ( | |
227 const BYTE *buff, /* 512 byte data block to be transmitted */ | |
228 BYTE token /* Data/Stop token */ | |
229 ) | |
230 { | |
231 BYTE resp, wc; | |
232 | |
233 | |
234 if (!wait_ready()) return 0; | |
235 | |
236 xmit_spi(token); /* Xmit data token */ | |
237 if (token != 0xFD) { /* Is data token */ | |
238 wc = 0; | |
239 do { /* Xmit the 512 byte data block to MMC */ | |
240 xmit_spi(*buff++); | |
241 xmit_spi(*buff++); | |
242 } while (--wc); | |
243 xmit_spi(0xFF); /* CRC (Dummy) */ | |
244 xmit_spi(0xFF); | |
245 resp = rcvr_spi(); /* Reveive data response */ | |
246 if ((resp & 0x1F) != 0x05) /* If not accepted, return with error */ | |
247 return 0; | |
248 } | |
249 | |
250 return 1; | |
251 } | |
252 | |
253 | |
254 | |
255 /*-----------------------------------------------------------------------*/ | |
256 /* Send a command packet to MMC */ | |
257 /*-----------------------------------------------------------------------*/ | |
258 | |
259 static | |
260 BYTE send_cmd ( /* Returns R1 resp (bit7==1:Send failed) */ | |
261 BYTE cmd, /* Command index */ | |
262 DWORD arg /* Argument */ | |
263 ) | |
264 { | |
265 BYTE n, res; | |
266 | |
267 | |
268 if (cmd & 0x80) { /* ACMD<n> is the command sequense of CMD55-CMD<n> */ | |
269 cmd &= 0x7F; | |
270 res = send_cmd(CMD55, 0); | |
271 if (res > 1) return res; | |
272 } | |
273 | |
274 /* Select the card and wait for ready */ | |
275 deselect(); | |
276 if (!select()) return 0xFF; | |
277 | |
278 /* Send command packet */ | |
279 xmit_spi(0x40 | cmd); /* Start + Command index */ | |
280 xmit_spi((BYTE)(arg >> 24)); /* Argument[31..24] */ | |
281 xmit_spi((BYTE)(arg >> 16)); /* Argument[23..16] */ | |
282 xmit_spi((BYTE)(arg >> 8)); /* Argument[15..8] */ | |
283 xmit_spi((BYTE)arg); /* Argument[7..0] */ | |
284 n = 0x01; /* Dummy CRC + Stop */ | |
285 if (cmd == CMD0) n = 0x95; /* Valid CRC for CMD0(0) */ | |
286 if (cmd == CMD8) n = 0x87; /* Valid CRC for CMD8(0x1AA) */ | |
287 xmit_spi(n); | |
288 | |
289 /* Receive command response */ | |
290 if (cmd == CMD12) rcvr_spi(); /* Skip a stuff byte when stop reading */ | |
291 n = 10; /* Wait for a valid response in timeout of 10 attempts */ | |
292 do | |
293 res = rcvr_spi(); | |
294 while ((res & 0x80) && --n); | |
295 | |
296 return res; /* Return with the response value */ | |
297 } | |
298 | |
299 | |
300 | |
301 /*-------------------------------------------------------------------------- | |
302 | |
303 Public Functions | |
304 | |
305 ---------------------------------------------------------------------------*/ | |
306 | |
307 | |
308 /*-----------------------------------------------------------------------*/ | |
309 /* Initialize Disk Drive */ | |
310 /*-----------------------------------------------------------------------*/ | |
311 | |
312 DSTATUS disk_initialize ( | |
313 BYTE drv /* Physical drive nmuber (0) */ | |
314 ) | |
315 { | |
316 BYTE n, cmd, ty, ocr[4]; | |
317 | |
318 | |
319 if (drv) return STA_NOINIT; /* Supports only single drive */ | |
320 if (Stat & STA_NODISK) return Stat; /* No card in the socket */ | |
321 | |
322 power_on(); /* Force socket power on */ | |
323 FCLK_SLOW(); | |
324 for (n = 10; n; n--) rcvr_spi(); /* 80 dummy clocks */ | |
325 | |
326 ty = 0; | |
327 if (send_cmd(CMD0, 0) == 1) { /* Enter Idle state */ | |
328 Timer1 = 100; /* Initialization timeout of 1000 msec */ | |
329 if (send_cmd(CMD8, 0x1AA) == 1) { /* SDv2? */ | |
330 for (n = 0; n < 4; n++) ocr[n] = rcvr_spi(); /* Get trailing return value of R7 resp */ | |
331 if (ocr[2] == 0x01 && ocr[3] == 0xAA) { /* The card can work at vdd range of 2.7-3.6V */ | |
332 while (Timer1 && send_cmd(ACMD41, 1UL << 30)); /* Wait for leaving idle state (ACMD41 with HCS bit) */ | |
333 if (Timer1 && send_cmd(CMD58, 0) == 0) { /* Check CCS bit in the OCR */ | |
334 for (n = 0; n < 4; n++) ocr[n] = rcvr_spi(); | |
335 ty = (ocr[0] & 0x40) ? CT_SD2 | CT_BLOCK : CT_SD2; /* SDv2 */ | |
336 } | |
337 } | |
338 } else { /* SDv1 or MMCv3 */ | |
339 if (send_cmd(ACMD41, 0) <= 1) { | |
340 ty = CT_SD1; cmd = ACMD41; /* SDv1 */ | |
341 } else { | |
342 ty = CT_MMC; cmd = CMD1; /* MMCv3 */ | |
343 } | |
344 while (Timer1 && send_cmd(cmd, 0)); /* Wait for leaving idle state */ | |
345 if (!Timer1 || send_cmd(CMD16, 512) != 0) /* Set R/W block length to 512 */ | |
346 ty = 0; | |
347 } | |
348 } | |
349 CardType = ty; | |
350 deselect(); | |
351 | |
352 if (ty) { /* Initialization succeded */ | |
353 Stat &= ~STA_NOINIT; /* Clear STA_NOINIT */ | |
354 FCLK_FAST(); | |
355 } else { /* Initialization failed */ | |
356 power_off(); | |
357 } | |
358 | |
359 return Stat; | |
360 } | |
361 | |
362 | |
363 | |
364 /*-----------------------------------------------------------------------*/ | |
365 /* Get Disk Status */ | |
366 /*-----------------------------------------------------------------------*/ | |
367 | |
368 DSTATUS disk_status ( | |
369 BYTE drv /* Physical drive nmuber (0) */ | |
370 ) | |
371 { | |
372 if (drv) return STA_NOINIT; /* Supports only single drive */ | |
373 return Stat; | |
374 } | |
375 | |
376 | |
377 | |
378 /*-----------------------------------------------------------------------*/ | |
379 /* Read Sector(s) */ | |
380 /*-----------------------------------------------------------------------*/ | |
381 | |
382 DRESULT disk_read ( | |
383 BYTE drv, /* Physical drive nmuber (0) */ | |
384 BYTE *buff, /* Pointer to the data buffer to store read data */ | |
385 DWORD sector, /* Start sector number (LBA) */ | |
386 BYTE count /* Sector count (1..255) */ | |
387 ) | |
388 { | |
389 if (drv || !count) return RES_PARERR; | |
390 if (Stat & STA_NOINIT) return RES_NOTRDY; | |
391 | |
392 if (!(CardType & CT_BLOCK)) sector *= 512; /* Convert to byte address if needed */ | |
393 | |
394 if (count == 1) { /* Single block read */ | |
395 if ((send_cmd(CMD17, sector) == 0) /* READ_SINGLE_BLOCK */ | |
396 && rcvr_datablock(buff, 512)) | |
397 count = 0; | |
398 } | |
399 else { /* Multiple block read */ | |
400 if (send_cmd(CMD18, sector) == 0) { /* READ_MULTIPLE_BLOCK */ | |
401 do { | |
402 if (!rcvr_datablock(buff, 512)) break; | |
403 buff += 512; | |
404 } while (--count); | |
405 send_cmd(CMD12, 0); /* STOP_TRANSMISSION */ | |
406 } | |
407 } | |
408 deselect(); | |
409 | |
410 return count ? RES_ERROR : RES_OK; | |
411 } | |
412 | |
413 | |
414 | |
415 /*-----------------------------------------------------------------------*/ | |
416 /* Write Sector(s) */ | |
417 /*-----------------------------------------------------------------------*/ | |
418 | |
419 DRESULT disk_write ( | |
420 BYTE drv, /* Physical drive nmuber (0) */ | |
421 const BYTE *buff, /* Pointer to the data to be written */ | |
422 DWORD sector, /* Start sector number (LBA) */ | |
423 BYTE count /* Sector count (1..255) */ | |
424 ) | |
425 { | |
426 if (drv || !count) return RES_PARERR; | |
427 if (Stat & STA_NOINIT) return RES_NOTRDY; | |
428 if (Stat & STA_PROTECT) return RES_WRPRT; | |
429 | |
430 if (!(CardType & CT_BLOCK)) sector *= 512; /* Convert to byte address if needed */ | |
431 | |
432 if (count == 1) { /* Single block write */ | |
433 if ((send_cmd(CMD24, sector) == 0) /* WRITE_BLOCK */ | |
434 && xmit_datablock(buff, 0xFE)) | |
435 count = 0; | |
436 } | |
437 else { /* Multiple block write */ | |
438 if (CardType & CT_SDC) send_cmd(ACMD23, count); | |
439 if (send_cmd(CMD25, sector) == 0) { /* WRITE_MULTIPLE_BLOCK */ | |
440 do { | |
441 if (!xmit_datablock(buff, 0xFC)) break; | |
442 buff += 512; | |
443 } while (--count); | |
444 if (!xmit_datablock(0, 0xFD)) /* STOP_TRAN token */ | |
445 count = 1; | |
446 } | |
447 } | |
448 deselect(); | |
449 | |
450 return count ? RES_ERROR : RES_OK; | |
451 } | |
452 | |
453 | |
454 | |
455 /*-----------------------------------------------------------------------*/ | |
456 /* Miscellaneous Functions */ | |
457 /*-----------------------------------------------------------------------*/ | |
458 | |
459 DRESULT disk_ioctl ( | |
460 BYTE drv, /* Physical drive nmuber (0) */ | |
461 BYTE ctrl, /* Control code */ | |
462 void *buff /* Buffer to send/receive control data */ | |
463 ) | |
464 { | |
465 DRESULT res; | |
466 BYTE n, csd[16], *ptr = buff; | |
467 WORD csize; | |
468 | |
469 | |
470 if (drv) return RES_PARERR; | |
471 | |
472 res = RES_ERROR; | |
473 | |
474 if (ctrl == CTRL_POWER) { | |
475 switch (ptr[0]) { | |
476 case 0: /* Sub control code (POWER_OFF) */ | |
477 power_off(); /* Power off */ | |
478 res = RES_OK; | |
479 break; | |
480 case 1: /* Sub control code (POWER_GET) */ | |
481 ptr[1] = (BYTE)power_status(); | |
482 res = RES_OK; | |
483 break; | |
484 default : | |
485 res = RES_PARERR; | |
486 } | |
487 } | |
488 else { | |
489 if (Stat & STA_NOINIT) return RES_NOTRDY; | |
490 | |
491 switch (ctrl) { | |
492 case CTRL_SYNC : /* Make sure that no pending write process. Do not remove this or written sector might not left updated. */ | |
493 if (select()) { | |
494 deselect(); | |
495 res = RES_OK; | |
496 } | |
497 break; | |
498 | |
499 case GET_SECTOR_COUNT : /* Get number of sectors on the disk (DWORD) */ | |
500 if ((send_cmd(CMD9, 0) == 0) && rcvr_datablock(csd, 16)) { | |
501 if ((csd[0] >> 6) == 1) { /* SDC ver 2.00 */ | |
502 csize = csd[9] + ((WORD)csd[8] << 8) + 1; | |
503 *(DWORD*)buff = (DWORD)csize << 10; | |
504 } else { /* SDC ver 1.XX or MMC*/ | |
505 n = (csd[5] & 15) + ((csd[10] & 128) >> 7) + ((csd[9] & 3) << 1) + 2; | |
506 csize = (csd[8] >> 6) + ((WORD)csd[7] << 2) + ((WORD)(csd[6] & 3) << 10) + 1; | |
507 *(DWORD*)buff = (DWORD)csize << (n - 9); | |
508 } | |
509 res = RES_OK; | |
510 } | |
511 break; | |
512 | |
513 case GET_SECTOR_SIZE : /* Get R/W sector size (WORD) */ | |
514 *(WORD*)buff = 512; | |
515 res = RES_OK; | |
516 break; | |
517 | |
518 case GET_BLOCK_SIZE : /* Get erase block size in unit of sector (DWORD) */ | |
519 if (CardType & CT_SD2) { /* SDv2? */ | |
520 if (send_cmd(ACMD13, 0) == 0) { /* Read SD status */ | |
521 rcvr_spi(); | |
522 if (rcvr_datablock(csd, 16)) { /* Read partial block */ | |
523 for (n = 64 - 16; n; n--) rcvr_spi(); /* Purge trailing data */ | |
524 *(DWORD*)buff = 16UL << (csd[10] >> 4); | |
525 res = RES_OK; | |
526 } | |
527 } | |
528 } else { /* SDv1 or MMCv3 */ | |
529 if ((send_cmd(CMD9, 0) == 0) && rcvr_datablock(csd, 16)) { /* Read CSD */ | |
530 if (CardType & CT_SD1) { /* SDv1 */ | |
531 *(DWORD*)buff = (((csd[10] & 63) << 1) + ((WORD)(csd[11] & 128) >> 7) + 1) << ((csd[13] >> 6) - 1); | |
532 } else { /* MMCv3 */ | |
533 *(DWORD*)buff = ((WORD)((csd[10] & 124) >> 2) + 1) * (((csd[11] & 3) << 3) + ((csd[11] & 224) >> 5) + 1); | |
534 } | |
535 res = RES_OK; | |
536 } | |
537 } | |
538 break; | |
539 | |
540 case MMC_GET_TYPE : /* Get card type flags (1 byte) */ | |
541 *ptr = CardType; | |
542 res = RES_OK; | |
543 break; | |
544 | |
545 case MMC_GET_CSD : /* Receive CSD as a data block (16 bytes) */ | |
546 if (send_cmd(CMD9, 0) == 0 /* READ_CSD */ | |
547 && rcvr_datablock(ptr, 16)) | |
548 res = RES_OK; | |
549 break; | |
550 | |
551 case MMC_GET_CID : /* Receive CID as a data block (16 bytes) */ | |
552 if (send_cmd(CMD10, 0) == 0 /* READ_CID */ | |
553 && rcvr_datablock(ptr, 16)) | |
554 res = RES_OK; | |
555 break; | |
556 | |
557 case MMC_GET_OCR : /* Receive OCR as an R3 resp (4 bytes) */ | |
558 if (send_cmd(CMD58, 0) == 0) { /* READ_OCR */ | |
559 for (n = 4; n; n--) *ptr++ = rcvr_spi(); | |
560 res = RES_OK; | |
561 } | |
562 break; | |
563 | |
564 case MMC_GET_SDSTAT : /* Receive SD statsu as a data block (64 bytes) */ | |
565 if (send_cmd(ACMD13, 0) == 0) { /* SD_STATUS */ | |
566 rcvr_spi(); | |
567 if (rcvr_datablock(ptr, 64)) | |
568 res = RES_OK; | |
569 } | |
570 break; | |
571 | |
572 default: | |
573 res = RES_PARERR; | |
574 } | |
575 | |
576 deselect(); | |
577 } | |
578 | |
579 return res; | |
580 } | |
581 | |
582 | |
583 | |
584 /*-----------------------------------------------------------------------*/ | |
585 /* Device Timer Interrupt Procedure */ | |
586 /*-----------------------------------------------------------------------*/ | |
587 /* This function must be called in period of 10ms */ | |
588 | |
589 void disk_timerproc (void) | |
590 { | |
591 BYTE n, s; | |
592 | |
593 | |
594 n = Timer1; /* 100Hz decrement timer */ | |
595 if (n) Timer1 = --n; | |
596 n = Timer2; | |
597 if (n) Timer2 = --n; | |
598 | |
599 s = Stat; | |
600 | |
601 if (SOCKWP) /* Write protected */ | |
602 s |= STA_PROTECT; | |
603 else /* Write enabled */ | |
604 s &= ~STA_PROTECT; | |
605 | |
606 if (SOCKINS) /* Card inserted */ | |
607 s &= ~STA_NODISK; | |
608 else /* Socket empty */ | |
609 s |= (STA_NODISK | STA_NOINIT); | |
610 | |
611 Stat = s; /* Update MMC status */ | |
612 } |