summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJens Arnold <amiconn@rockbox.org>2008-09-14 20:33:24 +0000
committerJens Arnold <amiconn@rockbox.org>2008-09-14 20:33:24 +0000
commitb1a584a1b6fbc3d16d7dbbd8f2fac857a1332f60 (patch)
tree6e5e2a7d70563af7161804948dea2d004b2fc229
parentd4404d3de0a99b69720b25ba730af197ea7d6c0b (diff)
downloadrockbox-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.c6
-rw-r--r--firmware/drivers/ata_mmc.c395
-rw-r--r--firmware/export/hotswap.h6
-rw-r--r--firmware/target/arm/ata-sd-pp.c3
-rw-r--r--firmware/usbstack/usb_storage.c2
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
122struct 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 123static unsigned char block_buffer[2][BLOCK_SIZE+4];
125 int drive; 124static 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
136static struct block_cache_entry block_cache[NUMCACHES];
137static int current_cache = 0;
138 125
139/* globals for background copy and swap */ 126/* globals for background copy and swap */
140static const unsigned char *bcs_src = NULL; 127static const unsigned char *bcs_src = NULL;
@@ -146,8 +133,8 @@ static tCardInfo card_info[2];
146static int current_card = 0; 133static int current_card = 0;
147#endif 134#endif
148static bool last_mmc_status = false; 135static bool last_mmc_status = false;
149static int countdown; /* for mmc switch debouncing */ 136static int countdown = HZ/3; /* for mmc switch debouncing */
150static bool usb_activity; /* monitoring the USB bridge */ 137static bool usb_activity; /* monitoring the USB bridge */
151static long last_usb_activity; 138static 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);
166static int receive_cxd(unsigned char *buf); 153static int receive_cxd(unsigned char *buf);
167static int initialize_card(int card_no); 154static int initialize_card(int card_no);
168static void bg_copy_swap(void); 155static void bg_copy_swap(void);
169static int receive_block(unsigned char *inbuf, int size, long timeout); 156static int receive_block(unsigned char *inbuf, long timeout);
170static int send_block(int size, unsigned char start_token, long timeout); 157static int send_block(unsigned char start_token, long timeout);
171static int cache_block(IF_MV2(int drive,) unsigned long blocknum,
172 int size, long timeout);
173static void mmc_tick(void); 158static void mmc_tick(void);
174 159
175/* implementation */ 160/* implementation */
@@ -402,7 +387,8 @@ static int receive_cxd(unsigned char *buf)
402 387
403static int initialize_card(int card_no) 388static 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 */
531static void bg_copy_swap(void) 509static 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 */
554static int receive_block(unsigned char *inbuf, int size, long timeout) 531static 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. */
596static int send_block(int size, unsigned char start_token, long timeout) 573static 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
635static 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
675int ata_read_sectors(IF_MV2(int drive,) 612int 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
24typedef struct 26typedef 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 }