diff options
author | Jens Arnold <amiconn@rockbox.org> | 2008-09-14 20:33:24 +0000 |
---|---|---|
committer | Jens Arnold <amiconn@rockbox.org> | 2008-09-14 20:33:24 +0000 |
commit | b1a584a1b6fbc3d16d7dbbd8f2fac857a1332f60 (patch) | |
tree | 6e5e2a7d70563af7161804948dea2d004b2fc229 | |
parent | d4404d3de0a99b69720b25ba730af197ea7d6c0b (diff) | |
download | rockbox-b1a584a1b6fbc3d16d7dbbd8f2fac857a1332f60.tar.gz rockbox-b1a584a1b6fbc3d16d7dbbd8f2fac857a1332f60.zip |
Simplify & fix the MMC driver. After more than 3 years I found that the MMC specs were a bit misleading, and the 'large' MMC which state a block size of 1024 or 2048 bytes and no partial read and/or partial write capability are happily accepting a block size of 512 bytes. So go KISS and remove all the variable/partial block handling code. This fixes the driver for the Transcend 4GB MMCplus, which doesn't cope when we actually set the 2048 byte block size it states. It also makes write operations involving small blocks faster and more reliable. * Note: The 4GB Transcend still doesn't work when plugged at boot, but works when hotplugged.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@18515 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r-- | apps/debug_menu.c | 6 | ||||
-rw-r--r-- | firmware/drivers/ata_mmc.c | 395 | ||||
-rw-r--r-- | firmware/export/hotswap.h | 6 | ||||
-rw-r--r-- | firmware/target/arm/ata-sd-pp.c | 3 | ||||
-rw-r--r-- | firmware/usbstack/usb_storage.c | 2 |
5 files changed, 125 insertions, 287 deletions
diff --git a/apps/debug_menu.c b/apps/debug_menu.c index 4d9be69ba5..ad19c3a7b2 100644 --- a/apps/debug_menu.c +++ b/apps/debug_menu.c | |||
@@ -1784,11 +1784,7 @@ static int disk_callback(int btn, struct gui_synclist *lists) | |||
1784 | CARDTYPE " v%s", temp < 5 ? | 1784 | CARDTYPE " v%s", temp < 5 ? |
1785 | spec_vers[temp] : "?.?"); | 1785 | spec_vers[temp] : "?.?"); |
1786 | simplelist_addline(SIMPLELIST_ADD_LINE, | 1786 | simplelist_addline(SIMPLELIST_ADD_LINE, |
1787 | "Blocks: 0x%06lx", card->numblocks); | 1787 | "Blocks: 0x%08lx", card->numblocks); |
1788 | simplelist_addline(SIMPLELIST_ADD_LINE, | ||
1789 | "Blksz.: %d P:%c%c", card->blocksize, | ||
1790 | card_extract_bits(card->csd, 48, 1) ? 'R' : '-', | ||
1791 | card_extract_bits(card->csd, 106, 1) ? 'W' : '-'); | ||
1792 | output_dyn_value(pbuf, sizeof pbuf, card->speed / 1000, | 1788 | output_dyn_value(pbuf, sizeof pbuf, card->speed / 1000, |
1793 | kbit_units, false); | 1789 | kbit_units, false); |
1794 | simplelist_addline(SIMPLELIST_ADD_LINE, | 1790 | simplelist_addline(SIMPLELIST_ADD_LINE, |
diff --git a/firmware/drivers/ata_mmc.c b/firmware/drivers/ata_mmc.c index e1d42feb44..da9f0d69fe 100644 --- a/firmware/drivers/ata_mmc.c +++ b/firmware/drivers/ata_mmc.c | |||
@@ -37,8 +37,7 @@ | |||
37 | #include "bitswap.h" | 37 | #include "bitswap.h" |
38 | #include "disk.h" /* for mount/unmount */ | 38 | #include "disk.h" /* for mount/unmount */ |
39 | 39 | ||
40 | #define SECTOR_SIZE 512 | 40 | #define BLOCK_SIZE 512 /* fixed */ |
41 | #define MAX_BLOCK_SIZE 2048 | ||
42 | 41 | ||
43 | /* Command definitions */ | 42 | /* Command definitions */ |
44 | #define CMD_GO_IDLE_STATE 0x40 /* R1 */ | 43 | #define CMD_GO_IDLE_STATE 0x40 /* R1 */ |
@@ -119,22 +118,10 @@ static const unsigned char dummy[] = { | |||
119 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF | 118 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF |
120 | }; | 119 | }; |
121 | 120 | ||
122 | struct block_cache_entry { | 121 | /* 2 buffers used alternatively for writing, including start token, |
123 | bool inuse; | 122 | * dummy CRC and an extra byte to keep word alignment. */ |
124 | #ifdef HAVE_MULTIVOLUME | 123 | static unsigned char block_buffer[2][BLOCK_SIZE+4]; |
125 | int drive; | 124 | static int current_buffer = 0; |
126 | #endif | ||
127 | unsigned long blocknum; | ||
128 | unsigned char data[MAX_BLOCK_SIZE+4]; | ||
129 | /* include start token, dummy crc, and an extra byte at the start | ||
130 | * to keep the data word aligned. */ | ||
131 | }; | ||
132 | |||
133 | /* 2 buffers used alternatively for writing, and also for reading | ||
134 | * and sub-block writing if block size > sector size */ | ||
135 | #define NUMCACHES 2 | ||
136 | static struct block_cache_entry block_cache[NUMCACHES]; | ||
137 | static int current_cache = 0; | ||
138 | 125 | ||
139 | /* globals for background copy and swap */ | 126 | /* globals for background copy and swap */ |
140 | static const unsigned char *bcs_src = NULL; | 127 | static const unsigned char *bcs_src = NULL; |
@@ -146,8 +133,8 @@ static tCardInfo card_info[2]; | |||
146 | static int current_card = 0; | 133 | static int current_card = 0; |
147 | #endif | 134 | #endif |
148 | static bool last_mmc_status = false; | 135 | static bool last_mmc_status = false; |
149 | static int countdown; /* for mmc switch debouncing */ | 136 | static int countdown = HZ/3; /* for mmc switch debouncing */ |
150 | static bool usb_activity; /* monitoring the USB bridge */ | 137 | static bool usb_activity; /* monitoring the USB bridge */ |
151 | static long last_usb_activity; | 138 | static long last_usb_activity; |
152 | 139 | ||
153 | /* private function declarations */ | 140 | /* private function declarations */ |
@@ -166,10 +153,8 @@ static int send_cmd(int cmd, unsigned long parameter, unsigned char *response); | |||
166 | static int receive_cxd(unsigned char *buf); | 153 | static int receive_cxd(unsigned char *buf); |
167 | static int initialize_card(int card_no); | 154 | static int initialize_card(int card_no); |
168 | static void bg_copy_swap(void); | 155 | static void bg_copy_swap(void); |
169 | static int receive_block(unsigned char *inbuf, int size, long timeout); | 156 | static int receive_block(unsigned char *inbuf, long timeout); |
170 | static int send_block(int size, unsigned char start_token, long timeout); | 157 | static int send_block(unsigned char start_token, long timeout); |
171 | static int cache_block(IF_MV2(int drive,) unsigned long blocknum, | ||
172 | int size, long timeout); | ||
173 | static void mmc_tick(void); | 158 | static void mmc_tick(void); |
174 | 159 | ||
175 | /* implementation */ | 160 | /* implementation */ |
@@ -402,7 +387,8 @@ static int receive_cxd(unsigned char *buf) | |||
402 | 387 | ||
403 | static int initialize_card(int card_no) | 388 | static int initialize_card(int card_no) |
404 | { | 389 | { |
405 | int rc, i, temp; | 390 | int rc, i; |
391 | int blk_exp, ts_exp, taac_exp; | ||
406 | unsigned char response[5]; | 392 | unsigned char response[5]; |
407 | tCardInfo *card = &card_info[card_no]; | 393 | tCardInfo *card = &card_info[card_no]; |
408 | 394 | ||
@@ -419,7 +405,7 @@ static int initialize_card(int card_no) | |||
419 | mmc_status = MMC_TOUCHED; | 405 | mmc_status = MMC_TOUCHED; |
420 | /* switch to SPI mode */ | 406 | /* switch to SPI mode */ |
421 | send_cmd(CMD_GO_IDLE_STATE, 0, response); | 407 | send_cmd(CMD_GO_IDLE_STATE, 0, response); |
422 | if (response[0] != 0x01) | 408 | if (response[0] != 0x01) |
423 | return -1; /* error response */ | 409 | return -1; /* error response */ |
424 | 410 | ||
425 | /* initialize card */ | 411 | /* initialize card */ |
@@ -451,38 +437,30 @@ static int initialize_card(int card_no) | |||
451 | if (rc) | 437 | if (rc) |
452 | return rc * 10 - 6; | 438 | return rc * 10 - 6; |
453 | 439 | ||
454 | /* check block sizes */ | 440 | blk_exp = card_extract_bits(card->csd, 44, 4); |
455 | card->block_exp = card_extract_bits(card->csd, 44, 4); | 441 | if (blk_exp < 9) /* block size < 512 bytes not supported */ |
456 | card->blocksize = 1 << card->block_exp; | ||
457 | if ((card_extract_bits(card->csd, 102, 4) != card->block_exp) | ||
458 | || card->blocksize > MAX_BLOCK_SIZE) | ||
459 | { | ||
460 | return -7; | 442 | return -7; |
461 | } | ||
462 | 443 | ||
463 | if (card->blocksize != SECTOR_SIZE) | 444 | card->numblocks = (card_extract_bits(card->csd, 54, 12) + 1) |
464 | { | 445 | << (card_extract_bits(card->csd, 78, 3) + 2 + blk_exp - 9); |
465 | rc = send_cmd(CMD_SET_BLOCKLEN, card->blocksize, response); | 446 | card->blocksize = BLOCK_SIZE; |
466 | if (rc) | ||
467 | return rc * 10 - 8; | ||
468 | } | ||
469 | 447 | ||
470 | /* max transmission speed, clock divider */ | 448 | /* max transmission speed, clock divider */ |
471 | temp = card_extract_bits(card->csd, 29, 3); | 449 | ts_exp = card_extract_bits(card->csd, 29, 3); |
472 | temp = (temp > 3) ? 3 : temp; | 450 | ts_exp = (ts_exp > 3) ? 3 : ts_exp; |
473 | card->speed = mantissa[card_extract_bits(card->csd, 25, 4)] | 451 | card->speed = mantissa[card_extract_bits(card->csd, 25, 4)] |
474 | * exponent[temp + 4]; | 452 | * exponent[ts_exp + 4]; |
475 | card->bitrate_register = (FREQ/4-1) / card->speed; | 453 | card->bitrate_register = (FREQ/4-1) / card->speed; |
476 | 454 | ||
477 | /* NSAC, TSAC, read timeout */ | 455 | /* NSAC, TSAC, read timeout */ |
478 | card->nsac = 100 * card_extract_bits(card->csd, 16, 8); | 456 | card->nsac = 100 * card_extract_bits(card->csd, 16, 8); |
479 | card->tsac = mantissa[card_extract_bits(card->csd, 9, 4)]; | 457 | card->tsac = mantissa[card_extract_bits(card->csd, 9, 4)]; |
480 | temp = card_extract_bits(card->csd, 13, 3); | 458 | taac_exp = card_extract_bits(card->csd, 13, 3); |
481 | card->read_timeout = ((FREQ/4) / (card->bitrate_register + 1) | 459 | card->read_timeout = ((FREQ/4) / (card->bitrate_register + 1) |
482 | * card->tsac / exponent[9 - temp] | 460 | * card->tsac / exponent[9 - taac_exp] |
483 | + (10 * card->nsac)); | 461 | + (10 * card->nsac)); |
484 | card->read_timeout /= 8; /* clocks -> bytes */ | 462 | card->read_timeout /= 8; /* clocks -> bytes */ |
485 | card->tsac = card->tsac * exponent[temp] / 10; | 463 | card->tsac = card->tsac * exponent[taac_exp] / 10; |
486 | 464 | ||
487 | /* r2w_factor, write timeout */ | 465 | /* r2w_factor, write timeout */ |
488 | card->r2w_factor = 1 << card_extract_bits(card->csd, 99, 3); | 466 | card->r2w_factor = 1 << card_extract_bits(card->csd, 99, 3); |
@@ -494,14 +472,14 @@ static int initialize_card(int card_no) | |||
494 | else | 472 | else |
495 | card->write_timeout = card->read_timeout * card->r2w_factor; | 473 | card->write_timeout = card->read_timeout * card->r2w_factor; |
496 | 474 | ||
497 | /* card size */ | ||
498 | card->numblocks = (card_extract_bits(card->csd, 54, 12) + 1) | ||
499 | * (1 << (card_extract_bits(card->csd, 78, 3) + 2)); | ||
500 | card->size = card->numblocks * card->blocksize; | ||
501 | |||
502 | /* switch to full speed */ | 475 | /* switch to full speed */ |
503 | setup_sci1(card->bitrate_register); | 476 | setup_sci1(card->bitrate_register); |
504 | 477 | ||
478 | /* always use 512 byte blocks */ | ||
479 | rc = send_cmd(CMD_SET_BLOCKLEN, BLOCK_SIZE, response); | ||
480 | if (rc) | ||
481 | return rc * 10 - 8; | ||
482 | |||
505 | /* get CID register */ | 483 | /* get CID register */ |
506 | rc = send_cmd(CMD_SEND_CID, 0, response); | 484 | rc = send_cmd(CMD_SEND_CID, 0, response); |
507 | if (rc) | 485 | if (rc) |
@@ -526,8 +504,8 @@ tCardInfo *mmc_card_info(int card_no) | |||
526 | return card; | 504 | return card; |
527 | } | 505 | } |
528 | 506 | ||
529 | /* copy and swap in the background. If destination is NULL, use the next | 507 | /* Copy and swap in the background |
530 | * block cache entry */ | 508 | * If destination is NULL, use the next block buffer */ |
531 | static void bg_copy_swap(void) | 509 | static void bg_copy_swap(void) |
532 | { | 510 | { |
533 | if (!bcs_len) | 511 | if (!bcs_len) |
@@ -535,9 +513,8 @@ static void bg_copy_swap(void) | |||
535 | 513 | ||
536 | if (!bcs_dest) | 514 | if (!bcs_dest) |
537 | { | 515 | { |
538 | current_cache = (current_cache + 1) % NUMCACHES; /* next cache */ | 516 | current_buffer ^= 1; /* toggle buffer */ |
539 | block_cache[current_cache].inuse = false; | 517 | bcs_dest = block_buffer[current_buffer] + 2; |
540 | bcs_dest = block_cache[current_cache].data + 2; | ||
541 | } | 518 | } |
542 | if (bcs_src) | 519 | if (bcs_src) |
543 | { | 520 | { |
@@ -551,7 +528,7 @@ static void bg_copy_swap(void) | |||
551 | 528 | ||
552 | /* Receive one block with dma, possibly swapping the previously received | 529 | /* Receive one block with dma, possibly swapping the previously received |
553 | * block in the background */ | 530 | * block in the background */ |
554 | static int receive_block(unsigned char *inbuf, int size, long timeout) | 531 | static int receive_block(unsigned char *inbuf, long timeout) |
555 | { | 532 | { |
556 | if (poll_byte(timeout) != DT_START_BLOCK) | 533 | if (poll_byte(timeout) != DT_START_BLOCK) |
557 | { | 534 | { |
@@ -568,7 +545,7 @@ static int receive_block(unsigned char *inbuf, int size, long timeout) | |||
568 | CHCR0 = 0; /* disable */ | 545 | CHCR0 = 0; /* disable */ |
569 | SAR0 = RDR1_ADDR; | 546 | SAR0 = RDR1_ADDR; |
570 | DAR0 = (unsigned long) inbuf; | 547 | DAR0 = (unsigned long) inbuf; |
571 | DTCR0 = size; | 548 | DTCR0 = BLOCK_SIZE; |
572 | CHCR0 = 0x4601; /* fixed source address, RXI1, enable */ | 549 | CHCR0 = 0x4601; /* fixed source address, RXI1, enable */ |
573 | DMAOR = 0x0001; | 550 | DMAOR = 0x0001; |
574 | SCR1 = (SCI_RE|SCI_RIE); /* kick off DMA */ | 551 | SCR1 = (SCI_RE|SCI_RIE); /* kick off DMA */ |
@@ -591,15 +568,15 @@ static int receive_block(unsigned char *inbuf, int size, long timeout) | |||
591 | return 0; | 568 | return 0; |
592 | } | 569 | } |
593 | 570 | ||
594 | /* Send one block with dma from the current block cache, possibly preparing | 571 | /* Send one block with dma from the current block buffer, possibly preparing |
595 | * the next block within the next block cache in the background. */ | 572 | * the next block within the next block buffer in the background. */ |
596 | static int send_block(int size, unsigned char start_token, long timeout) | 573 | static int send_block(unsigned char start_token, long timeout) |
597 | { | 574 | { |
598 | int rc = 0; | 575 | int rc = 0; |
599 | unsigned char *curbuf = block_cache[current_cache].data; | 576 | unsigned char *curbuf = block_buffer[current_buffer]; |
600 | 577 | ||
601 | curbuf[1] = fliptable[(signed char)start_token]; | 578 | curbuf[1] = fliptable[(signed char)start_token]; |
602 | *(unsigned short *)(curbuf + size + 2) = 0xFFFF; | 579 | *(unsigned short *)(curbuf + BLOCK_SIZE + 2) = 0xFFFF; |
603 | 580 | ||
604 | while (!(SSR1 & SCI_TEND)); /* wait for end of transfer */ | 581 | while (!(SSR1 & SCI_TEND)); /* wait for end of transfer */ |
605 | 582 | ||
@@ -610,7 +587,7 @@ static int send_block(int size, unsigned char start_token, long timeout) | |||
610 | CHCR0 = 0; /* disable */ | 587 | CHCR0 = 0; /* disable */ |
611 | SAR0 = (unsigned long)(curbuf + 1); | 588 | SAR0 = (unsigned long)(curbuf + 1); |
612 | DAR0 = TDR1_ADDR; | 589 | DAR0 = TDR1_ADDR; |
613 | DTCR0 = size + 3; /* start token + block + dummy crc */ | 590 | DTCR0 = BLOCK_SIZE + 3; /* start token + block + dummy crc */ |
614 | CHCR0 = 0x1701; /* fixed dest. address, TXI1, enable */ | 591 | CHCR0 = 0x1701; /* fixed dest. address, TXI1, enable */ |
615 | DMAOR = 0x0001; | 592 | DMAOR = 0x0001; |
616 | SCR1 = (SCI_TE|SCI_TIE); /* kick off DMA */ | 593 | SCR1 = (SCI_TE|SCI_TIE); /* kick off DMA */ |
@@ -632,64 +609,20 @@ static int send_block(int size, unsigned char start_token, long timeout) | |||
632 | return rc; | 609 | return rc; |
633 | } | 610 | } |
634 | 611 | ||
635 | static int cache_block(IF_MV2(int drive,) unsigned long blocknum, | ||
636 | int size, long timeout) | ||
637 | { | ||
638 | int rc, i; | ||
639 | unsigned char response; | ||
640 | |||
641 | /* check whether the block is already cached */ | ||
642 | for (i = 0; i < NUMCACHES; i++) | ||
643 | { | ||
644 | if (block_cache[i].inuse && (block_cache[i].blocknum == blocknum) | ||
645 | #ifdef HAVE_MULTIVOLUME | ||
646 | && (block_cache[i].drive == drive) | ||
647 | #endif | ||
648 | ) | ||
649 | { | ||
650 | current_cache = i; | ||
651 | bg_copy_swap(); | ||
652 | return 0; | ||
653 | } | ||
654 | } | ||
655 | /* not found: read the block */ | ||
656 | current_cache = (current_cache + 1) % NUMCACHES; | ||
657 | rc = send_cmd(CMD_READ_SINGLE_BLOCK, blocknum * size, &response); | ||
658 | if (rc) | ||
659 | return rc * 10 - 1; | ||
660 | |||
661 | block_cache[current_cache].inuse = false; | ||
662 | rc = receive_block(block_cache[current_cache].data + 2, size, timeout); | ||
663 | if (rc) | ||
664 | return rc * 10 - 2; | ||
665 | |||
666 | #ifdef HAVE_MULTIVOLUME | ||
667 | block_cache[current_cache].drive = drive; | ||
668 | #endif | ||
669 | block_cache[current_cache].blocknum = blocknum; | ||
670 | block_cache[current_cache].inuse = true; | ||
671 | |||
672 | return 0; | ||
673 | } | ||
674 | |||
675 | int ata_read_sectors(IF_MV2(int drive,) | 612 | int ata_read_sectors(IF_MV2(int drive,) |
676 | unsigned long start, | 613 | unsigned long start, |
677 | int incount, | 614 | int incount, |
678 | void* inbuf) | 615 | void* inbuf) |
679 | { | 616 | { |
680 | int rc = 0; | 617 | int rc = 0; |
681 | unsigned int blocksize, offset; | 618 | int lastblock = 0; |
682 | unsigned long c_addr, c_end_addr; | 619 | unsigned long end_block; |
683 | unsigned long c_block, c_end_block; | ||
684 | unsigned char response; | 620 | unsigned char response; |
685 | tCardInfo *card; | 621 | tCardInfo *card; |
686 | #ifndef HAVE_MULTIVOLUME | 622 | #ifndef HAVE_MULTIVOLUME |
687 | int drive = current_card; | 623 | int drive = current_card; |
688 | #endif | 624 | #endif |
689 | 625 | ||
690 | c_addr = start * SECTOR_SIZE; | ||
691 | c_end_addr = c_addr + incount * SECTOR_SIZE; | ||
692 | |||
693 | card = &card_info[drive]; | 626 | card = &card_info[drive]; |
694 | rc = select_card(drive); | 627 | rc = select_card(drive); |
695 | if (rc) | 628 | if (rc) |
@@ -697,88 +630,68 @@ int ata_read_sectors(IF_MV2(int drive,) | |||
697 | rc = rc * 10 - 1; | 630 | rc = rc * 10 - 1; |
698 | goto error; | 631 | goto error; |
699 | } | 632 | } |
700 | if (c_end_addr > card->size) | 633 | |
634 | end_block = start + incount; | ||
635 | if (end_block > card->numblocks) | ||
701 | { | 636 | { |
702 | rc = -2; | 637 | rc = -2; |
703 | goto error; | 638 | goto error; |
704 | } | 639 | } |
705 | 640 | ||
706 | blocksize = card->blocksize; | 641 | /* Some cards don't like reading the very last block with |
707 | offset = c_addr & (blocksize - 1); | 642 | * CMD_READ_MULTIPLE_BLOCK, so make sure this block is always |
708 | c_block = c_addr >> card->block_exp; | 643 | * read with CMD_READ_SINGLE_BLOCK. */ |
709 | c_end_block = c_end_addr >> card->block_exp; | 644 | if (end_block == card->numblocks) |
645 | lastblock = 1; | ||
646 | |||
647 | bcs_src = NULL; | ||
710 | bcs_dest = inbuf; | 648 | bcs_dest = inbuf; |
711 | 649 | ||
712 | if (offset) /* first partial block */ | 650 | if (incount > 1) |
713 | { | 651 | { |
714 | unsigned long len = MIN(c_end_addr - c_addr, blocksize - offset); | 652 | rc = send_cmd(CMD_READ_MULTIPLE_BLOCK, start * BLOCK_SIZE, &response); |
715 | 653 | /* MMC4.2: make multiplication conditional */ | |
716 | rc = cache_block(IF_MV2(drive,) c_block, blocksize, | ||
717 | card->read_timeout); | ||
718 | if (rc) | 654 | if (rc) |
719 | { | 655 | { |
720 | rc = rc * 10 - 3; | 656 | rc = rc * 10 - 3; |
721 | goto error; | 657 | goto error; |
722 | } | ||
723 | bcs_src = block_cache[current_cache].data + 2 + offset; | ||
724 | bcs_len = len; | ||
725 | inbuf += len; | ||
726 | c_addr += len; | ||
727 | c_block++; | ||
728 | } | ||
729 | /* some cards don't like reading the very last block with | ||
730 | * CMD_READ_MULTIPLE_BLOCK, so make sure this block is always | ||
731 | * read with CMD_READ_SINGLE_BLOCK. Let the 'last partial block' | ||
732 | * read catch this. */ | ||
733 | if (c_end_block == card->numblocks) | ||
734 | c_end_block--; | ||
735 | |||
736 | if (c_block < c_end_block) | ||
737 | { | ||
738 | int read_cmd = (c_end_block - c_block > 1) ? | ||
739 | CMD_READ_MULTIPLE_BLOCK : CMD_READ_SINGLE_BLOCK; | ||
740 | |||
741 | rc = send_cmd(read_cmd, c_addr, &response); | ||
742 | if (rc) | ||
743 | { | ||
744 | rc = rc * 10 - 4; | ||
745 | goto error; | ||
746 | } | 658 | } |
747 | while (c_block < c_end_block) | 659 | while (incount-- > lastblock) |
748 | { | 660 | { |
749 | rc = receive_block(inbuf, blocksize, card->read_timeout); | 661 | rc = receive_block(inbuf, card->read_timeout); |
750 | if (rc) | 662 | if (rc) |
751 | { | 663 | { |
752 | rc = rc * 10 - 5; | 664 | rc = rc * 10 - 4; |
753 | goto error; | 665 | goto error; |
754 | } | 666 | } |
755 | bcs_src = NULL; | 667 | bcs_len = BLOCK_SIZE; |
756 | bcs_len = blocksize; | 668 | inbuf += BLOCK_SIZE; |
757 | inbuf += blocksize; | 669 | start++; |
758 | c_addr += blocksize; | 670 | /* ^^ necessary for the abovementioned last block special case */ |
759 | c_block++; | ||
760 | } | 671 | } |
761 | if (read_cmd == CMD_READ_MULTIPLE_BLOCK) | 672 | rc = send_cmd(CMD_STOP_TRANSMISSION, 0, &response); |
673 | if (rc) | ||
762 | { | 674 | { |
763 | rc = send_cmd(CMD_STOP_TRANSMISSION, 0, &response); | 675 | rc = rc * 10 - 5; |
764 | if (rc) | 676 | goto error; |
765 | { | ||
766 | rc = rc * 10 - 6; | ||
767 | goto error; | ||
768 | } | ||
769 | } | 677 | } |
770 | } | 678 | } |
771 | if (c_addr < c_end_addr) /* last partial block */ | 679 | if (incount > 0) |
772 | { | 680 | { |
773 | rc = cache_block(IF_MV2(drive,) c_block, blocksize, | 681 | rc = send_cmd(CMD_READ_SINGLE_BLOCK, start * BLOCK_SIZE, &response); |
774 | card->read_timeout); | 682 | /* MMC4.2: make multiplication conditional */ |
683 | if (rc) | ||
684 | { | ||
685 | rc = rc * 10 - 6; | ||
686 | goto error; | ||
687 | } | ||
688 | rc = receive_block(inbuf, card->read_timeout); | ||
775 | if (rc) | 689 | if (rc) |
776 | { | 690 | { |
777 | rc = rc * 10 - 7; | 691 | rc = rc * 10 - 7; |
778 | goto error; | 692 | goto error; |
779 | } | 693 | } |
780 | bcs_src = block_cache[current_cache].data + 2; | 694 | bcs_len = BLOCK_SIZE; |
781 | bcs_len = c_end_addr - c_addr; | ||
782 | } | 695 | } |
783 | bg_copy_swap(); | 696 | bg_copy_swap(); |
784 | 697 | ||
@@ -795,18 +708,14 @@ int ata_write_sectors(IF_MV2(int drive,) | |||
795 | const void* buf) | 708 | const void* buf) |
796 | { | 709 | { |
797 | int rc = 0; | 710 | int rc = 0; |
798 | unsigned int blocksize, offset; | 711 | int write_cmd; |
799 | unsigned long c_addr, c_end_addr; | 712 | unsigned char start_token; |
800 | unsigned long c_block, c_end_block; | ||
801 | unsigned char response; | 713 | unsigned char response; |
802 | tCardInfo *card; | 714 | tCardInfo *card; |
803 | #ifndef HAVE_MULTIVOLUME | 715 | #ifndef HAVE_MULTIVOLUME |
804 | int drive = current_card; | 716 | int drive = current_card; |
805 | #endif | 717 | #endif |
806 | 718 | ||
807 | c_addr = start * SECTOR_SIZE; | ||
808 | c_end_addr = c_addr + count * SECTOR_SIZE; | ||
809 | |||
810 | card = &card_info[drive]; | 719 | card = &card_info[drive]; |
811 | rc = select_card(drive); | 720 | rc = select_card(drive); |
812 | if (rc) | 721 | if (rc) |
@@ -814,120 +723,56 @@ int ata_write_sectors(IF_MV2(int drive,) | |||
814 | rc = rc * 10 - 1; | 723 | rc = rc * 10 - 1; |
815 | goto error; | 724 | goto error; |
816 | } | 725 | } |
817 | 726 | ||
818 | if (c_end_addr > card->size) | 727 | if (start + count > card->numblocks) |
819 | panicf("Writing past end of card"); | 728 | panicf("Writing past end of card"); |
820 | 729 | ||
821 | blocksize = card->blocksize; | 730 | bcs_src = buf; |
822 | offset = c_addr & (blocksize - 1); | 731 | bcs_dest = NULL; /* next block buffer */ |
823 | c_block = c_addr >> card->block_exp; | 732 | bcs_len = BLOCK_SIZE; |
824 | c_end_block = c_end_addr >> card->block_exp; | 733 | bg_copy_swap(); |
825 | bcs_src = buf; | ||
826 | |||
827 | /* Special case: first block is trimmed at both ends. May only happen | ||
828 | * if (blocksize > 2 * sectorsize), i.e. blocksize == 2048 */ | ||
829 | if ((c_block == c_end_block) && offset) | ||
830 | c_end_block++; | ||
831 | 734 | ||
832 | if (c_block < c_end_block) | 735 | if (count > 1) |
833 | { | 736 | { |
834 | int write_cmd; | 737 | write_cmd = CMD_WRITE_MULTIPLE_BLOCK; |
835 | unsigned char start_token; | 738 | start_token = DT_START_WRITE_MULTIPLE; |
836 | 739 | } | |
837 | if (c_end_block - c_block > 1) | 740 | else |
838 | { | 741 | { |
839 | write_cmd = CMD_WRITE_MULTIPLE_BLOCK; | 742 | write_cmd = CMD_WRITE_BLOCK; |
840 | start_token = DT_START_WRITE_MULTIPLE; | 743 | start_token = DT_START_BLOCK; |
841 | } | 744 | } |
842 | else | 745 | rc = send_cmd(write_cmd, start * BLOCK_SIZE, &response); |
843 | { | 746 | /* MMC4.2: make multiplication conditional */ |
844 | write_cmd = CMD_WRITE_BLOCK; | 747 | if (rc) |
845 | start_token = DT_START_BLOCK; | 748 | { |
846 | } | 749 | rc = rc * 10 - 2; |
750 | goto error; | ||
751 | } | ||
847 | 752 | ||
848 | if (offset) | 753 | while (--count > 0) |
849 | { | 754 | { |
850 | unsigned long len = MIN(c_end_addr - c_addr, blocksize - offset); | 755 | bcs_dest = NULL; /* next block cache */ |
851 | 756 | bcs_len = BLOCK_SIZE; | |
852 | rc = cache_block(IF_MV2(drive,) c_block, blocksize, | 757 | rc = send_block(start_token, card->write_timeout); |
853 | card->read_timeout); | ||
854 | if (rc) | ||
855 | { | ||
856 | rc = rc * 10 - 2; | ||
857 | goto error; | ||
858 | } | ||
859 | bcs_dest = block_cache[current_cache].data + 2 + offset; | ||
860 | bcs_len = len; | ||
861 | c_addr -= offset; | ||
862 | } | ||
863 | else | ||
864 | { | ||
865 | bcs_dest = NULL; /* next block cache */ | ||
866 | bcs_len = blocksize; | ||
867 | } | ||
868 | bg_copy_swap(); | ||
869 | rc = send_cmd(write_cmd, c_addr, &response); | ||
870 | if (rc) | 758 | if (rc) |
871 | { | 759 | { |
872 | rc = rc * 10 - 3; | 760 | rc = rc * 10 - 3; |
873 | goto error; | 761 | goto error; |
874 | } | 762 | } |
875 | c_block++; /* early increment to simplify the loop */ | ||
876 | |||
877 | while (c_block < c_end_block) | ||
878 | { | ||
879 | bcs_dest = NULL; /* next block cache */ | ||
880 | bcs_len = blocksize; | ||
881 | rc = send_block(blocksize, start_token, card->write_timeout); | ||
882 | if (rc) | ||
883 | { | ||
884 | rc = rc * 10 - 4; | ||
885 | goto error; | ||
886 | } | ||
887 | c_addr += blocksize; | ||
888 | c_block++; | ||
889 | } | ||
890 | rc = send_block(blocksize, start_token, card->write_timeout); | ||
891 | if (rc) | ||
892 | { | ||
893 | rc = rc * 10 - 5; | ||
894 | goto error; | ||
895 | } | ||
896 | c_addr += blocksize; | ||
897 | /* c_block++ was done early */ | ||
898 | |||
899 | if (write_cmd == CMD_WRITE_MULTIPLE_BLOCK) | ||
900 | { | ||
901 | response = DT_STOP_TRAN; | ||
902 | write_transfer(&response, 1); | ||
903 | poll_busy(card->write_timeout); | ||
904 | } | ||
905 | } | 763 | } |
906 | 764 | rc = send_block(start_token, card->write_timeout); | |
907 | if (c_addr < c_end_addr) /* last partial block */ | 765 | if (rc) |
908 | { | 766 | { |
909 | rc = cache_block(IF_MV2(drive,) c_block, blocksize, | 767 | rc = rc * 10 - 4; |
910 | card->read_timeout); | 768 | goto error; |
911 | if (rc) | 769 | } |
912 | { | 770 | |
913 | rc = rc * 10 - 6; | 771 | if (write_cmd == CMD_WRITE_MULTIPLE_BLOCK) |
914 | goto error; | 772 | { |
915 | } | 773 | response = DT_STOP_TRAN; |
916 | bcs_dest = block_cache[current_cache].data + 2; | 774 | write_transfer(&response, 1); |
917 | bcs_len = c_end_addr - c_addr; | 775 | poll_busy(card->write_timeout); |
918 | bg_copy_swap(); | ||
919 | rc = send_cmd(CMD_WRITE_BLOCK, c_addr, &response); | ||
920 | if (rc) | ||
921 | { | ||
922 | rc = rc * 10 - 7; | ||
923 | goto error; | ||
924 | } | ||
925 | rc = send_block(blocksize, DT_START_BLOCK, card->write_timeout); | ||
926 | if (rc) | ||
927 | { | ||
928 | rc = rc * 10 - 8; | ||
929 | goto error; | ||
930 | } | ||
931 | } | 776 | } |
932 | 777 | ||
933 | error: | 778 | error: |
@@ -1017,7 +862,7 @@ bool mmc_touched(void) | |||
1017 | { | 862 | { |
1018 | if (mmc_status == MMC_UNKNOWN) /* try to detect */ | 863 | if (mmc_status == MMC_UNKNOWN) /* try to detect */ |
1019 | { | 864 | { |
1020 | unsigned char response; | 865 | unsigned char response; |
1021 | 866 | ||
1022 | mutex_lock(&mmc_mutex); | 867 | mutex_lock(&mmc_mutex); |
1023 | setup_sci1(7); /* safe value */ | 868 | setup_sci1(7); /* safe value */ |
@@ -1064,7 +909,7 @@ static void mmc_tick(void) | |||
1064 | if (current_status != last_mmc_status) | 909 | if (current_status != last_mmc_status) |
1065 | { | 910 | { |
1066 | last_mmc_status = current_status; | 911 | last_mmc_status = current_status; |
1067 | countdown = 30; | 912 | countdown = HZ/3; |
1068 | } | 913 | } |
1069 | else | 914 | else |
1070 | { | 915 | { |
diff --git a/firmware/export/hotswap.h b/firmware/export/hotswap.h index 4b3b5a52e0..d01c467adf 100644 --- a/firmware/export/hotswap.h +++ b/firmware/export/hotswap.h | |||
@@ -21,9 +21,11 @@ | |||
21 | #ifndef __HOTSWAP_H__ | 21 | #ifndef __HOTSWAP_H__ |
22 | #define __HOTSWAP_H__ | 22 | #define __HOTSWAP_H__ |
23 | 23 | ||
24 | #include <stdbool.h> | ||
25 | |||
24 | typedef struct | 26 | typedef struct |
25 | { | 27 | { |
26 | int initialized; | 28 | bool initialized; |
27 | unsigned char bitrate_register; | 29 | unsigned char bitrate_register; |
28 | unsigned long read_timeout; /* n * 8 clock cycles */ | 30 | unsigned long read_timeout; /* n * 8 clock cycles */ |
29 | unsigned long write_timeout; /* n * 8 clock cycles */ | 31 | unsigned long write_timeout; /* n * 8 clock cycles */ |
@@ -35,10 +37,8 @@ typedef struct | |||
35 | unsigned int nsac; /* clock cycles */ | 37 | unsigned int nsac; /* clock cycles */ |
36 | unsigned long tsac; /* n * 0.1 ns */ | 38 | unsigned long tsac; /* n * 0.1 ns */ |
37 | unsigned int r2w_factor; | 39 | unsigned int r2w_factor; |
38 | unsigned long size; /* size in bytes */ | ||
39 | unsigned long numblocks; /* size in flash blocks */ | 40 | unsigned long numblocks; /* size in flash blocks */ |
40 | unsigned int blocksize; /* block size in bytes */ | 41 | unsigned int blocksize; /* block size in bytes */ |
41 | unsigned int block_exp; /* block size exponent */ | ||
42 | } tCardInfo; | 42 | } tCardInfo; |
43 | 43 | ||
44 | #ifdef HAVE_ATA_SD | 44 | #ifdef HAVE_ATA_SD |
diff --git a/firmware/target/arm/ata-sd-pp.c b/firmware/target/arm/ata-sd-pp.c index ddefbf7fdb..fbbaf09b5d 100644 --- a/firmware/target/arm/ata-sd-pp.c +++ b/firmware/target/arm/ata-sd-pp.c | |||
@@ -1260,9 +1260,6 @@ tCardInfo *card_get_info_target(int card_no) | |||
1260 | for(i=0; i<4; i++) card.cid[i] = card_info[card_no].cid[3-i]; | 1260 | for(i=0; i<4; i++) card.cid[i] = card_info[card_no].cid[3-i]; |
1261 | card.numblocks = card_info[card_no].numblocks; | 1261 | card.numblocks = card_info[card_no].numblocks; |
1262 | card.blocksize = card_info[card_no].block_size; | 1262 | card.blocksize = card_info[card_no].block_size; |
1263 | card.size = card_info[card_no].capacity < 0xffffffff ? | ||
1264 | card_info[card_no].capacity : 0xffffffff; | ||
1265 | card.block_exp = card_info[card_no].block_exp; | ||
1266 | temp = card_extract_bits(card.csd, 29, 3); | 1263 | temp = card_extract_bits(card.csd, 29, 3); |
1267 | card.speed = mantissa[card_extract_bits(card.csd, 25, 4)] | 1264 | card.speed = mantissa[card_extract_bits(card.csd, 25, 4)] |
1268 | * exponent[temp > 2 ? 7 : temp + 4]; | 1265 | * exponent[temp > 2 ? 7 : temp + 4]; |
diff --git a/firmware/usbstack/usb_storage.c b/firmware/usbstack/usb_storage.c index 17b8bb7168..f774d14cbc 100644 --- a/firmware/usbstack/usb_storage.c +++ b/firmware/usbstack/usb_storage.c | |||
@@ -627,7 +627,7 @@ static void handle_scsi(struct command_block_wrapper* cbw) | |||
627 | unsigned int block_size_mult = 1; | 627 | unsigned int block_size_mult = 1; |
628 | #if defined(HAVE_ATA_SD) || defined(HAVE_HOTSWAP) | 628 | #if defined(HAVE_ATA_SD) || defined(HAVE_HOTSWAP) |
629 | tCardInfo* cinfo = card_get_info(lun); | 629 | tCardInfo* cinfo = card_get_info(lun); |
630 | if(cinfo->initialized==1 && cinfo->numblocks > 0) { | 630 | if(cinfo->initialized && cinfo->numblocks > 0) { |
631 | block_size = cinfo->blocksize; | 631 | block_size = cinfo->blocksize; |
632 | block_count = cinfo->numblocks; | 632 | block_count = cinfo->numblocks; |
633 | } | 633 | } |