diff options
author | Michael Sevakis <jethead71@rockbox.org> | 2007-06-30 02:08:27 +0000 |
---|---|---|
committer | Michael Sevakis <jethead71@rockbox.org> | 2007-06-30 02:08:27 +0000 |
commit | 1167e3c72f5d0d581b81fd2cb8f2580a1524ca5a (patch) | |
tree | 501f9901636d5586271067d0c157204e500a2cfd | |
parent | 189a5f812f47e43e5704a44c3abb85a4c37c8662 (diff) | |
download | rockbox-1167e3c72f5d0d581b81fd2cb8f2580a1524ca5a.tar.gz rockbox-1167e3c72f5d0d581b81fd2cb8f2580a1524ca5a.zip |
Accept FS#7134 - Sansa: external sd card support by Antonius Hellmann with some tweaks. All testers have given the green light. (Now for the RED ?? ;).
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@13741 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r-- | apps/debug_menu.c | 46 | ||||
-rw-r--r-- | apps/main.c | 3 | ||||
-rw-r--r-- | apps/misc.c | 3 | ||||
-rw-r--r-- | apps/screens.c | 4 | ||||
-rw-r--r-- | bootloader/main-pp.c | 20 | ||||
-rw-r--r-- | firmware/SOURCES | 3 | ||||
-rw-r--r-- | firmware/common/dir.c | 3 | ||||
-rw-r--r-- | firmware/common/disk.c | 16 | ||||
-rw-r--r-- | firmware/drivers/ata_mmc.c | 48 | ||||
-rw-r--r-- | firmware/export/ata_mmc.h | 24 | ||||
-rw-r--r-- | firmware/export/config-e200.h | 5 | ||||
-rw-r--r-- | firmware/export/config.h | 2 | ||||
-rw-r--r-- | firmware/export/hotswap.h | 59 | ||||
-rw-r--r-- | firmware/export/kernel.h | 4 | ||||
-rw-r--r-- | firmware/export/pp5024.h | 2 | ||||
-rw-r--r-- | firmware/hotswap.c | 58 | ||||
-rw-r--r-- | firmware/include/dir.h | 4 | ||||
-rw-r--r-- | firmware/target/arm/sandisk/sansa-e200/ata-e200.c | 1031 | ||||
-rw-r--r-- | firmware/target/arm/sandisk/sansa-e200/ata-target.h | 21 | ||||
-rw-r--r-- | firmware/target/arm/sandisk/sansa-e200/hotswap-target.h | 45 | ||||
-rw-r--r-- | firmware/target/arm/system-pp502x.c | 13 | ||||
-rw-r--r-- | firmware/usb.c | 4 |
22 files changed, 882 insertions, 536 deletions
diff --git a/apps/debug_menu.c b/apps/debug_menu.c index 0b39430d56..fe7d5b584b 100644 --- a/apps/debug_menu.c +++ b/apps/debug_menu.c | |||
@@ -59,7 +59,7 @@ | |||
59 | #include "fat.h" | 59 | #include "fat.h" |
60 | #include "mas.h" | 60 | #include "mas.h" |
61 | #include "eeprom_24cxx.h" | 61 | #include "eeprom_24cxx.h" |
62 | #ifdef HAVE_MMC | 62 | #if defined(HAVE_MMC) || defined(HAVE_HOTSWAP) |
63 | #include "ata_mmc.h" | 63 | #include "ata_mmc.h" |
64 | #endif | 64 | #endif |
65 | #if CONFIG_TUNER | 65 | #if CONFIG_TUNER |
@@ -1524,8 +1524,8 @@ static bool view_battery(void) | |||
1524 | #endif | 1524 | #endif |
1525 | 1525 | ||
1526 | #ifndef SIMULATOR | 1526 | #ifndef SIMULATOR |
1527 | #ifdef HAVE_MMC | 1527 | #if defined(HAVE_MMC) || defined(HAVE_HOTSWAP) |
1528 | static bool dbg_mmc_info(void) | 1528 | static bool dbg_card_info(void) |
1529 | { | 1529 | { |
1530 | bool done = false; | 1530 | bool done = false; |
1531 | int currval = 0; | 1531 | int currval = 0; |
@@ -1548,7 +1548,7 @@ static bool dbg_mmc_info(void) | |||
1548 | 1548 | ||
1549 | while (!done) | 1549 | while (!done) |
1550 | { | 1550 | { |
1551 | card = mmc_card_info(currval / 2); | 1551 | card = card_get_info(currval / 2); |
1552 | 1552 | ||
1553 | line = 0; | 1553 | line = 0; |
1554 | lcd_clear_display(); | 1554 | lcd_clear_display(); |
@@ -1564,29 +1564,29 @@ static bool dbg_mmc_info(void) | |||
1564 | 1564 | ||
1565 | strncpy(card_name, ((unsigned char*)card->cid) + 3, 6); | 1565 | strncpy(card_name, ((unsigned char*)card->cid) + 3, 6); |
1566 | snprintf(pbuf, sizeof(pbuf), "%s Rev %d.%d", card_name, | 1566 | snprintf(pbuf, sizeof(pbuf), "%s Rev %d.%d", card_name, |
1567 | (int) mmc_extract_bits(card->cid, 72, 4), | 1567 | (int) card_extract_bits(card->cid, 72, 4), |
1568 | (int) mmc_extract_bits(card->cid, 76, 4)); | 1568 | (int) card_extract_bits(card->cid, 76, 4)); |
1569 | lcd_puts(0, line++, pbuf); | 1569 | lcd_puts(0, line++, pbuf); |
1570 | snprintf(pbuf, sizeof(pbuf), "Prod: %d/%d", | 1570 | snprintf(pbuf, sizeof(pbuf), "Prod: %d/%d", |
1571 | (int) mmc_extract_bits(card->cid, 112, 4), | 1571 | (int) card_extract_bits(card->cid, 112, 4), |
1572 | (int) mmc_extract_bits(card->cid, 116, 4) + 1997); | 1572 | (int) card_extract_bits(card->cid, 116, 4) + 1997); |
1573 | lcd_puts(0, line++, pbuf); | 1573 | lcd_puts(0, line++, pbuf); |
1574 | snprintf(pbuf, sizeof(pbuf), "Ser#: 0x%08lx", | 1574 | snprintf(pbuf, sizeof(pbuf), "Ser#: 0x%08lx", |
1575 | mmc_extract_bits(card->cid, 80, 32)); | 1575 | card_extract_bits(card->cid, 80, 32)); |
1576 | lcd_puts(0, line++, pbuf); | 1576 | lcd_puts(0, line++, pbuf); |
1577 | snprintf(pbuf, sizeof(pbuf), "M=%02x, O=%04x", | 1577 | snprintf(pbuf, sizeof(pbuf), "M=%02x, O=%04x", |
1578 | (int) mmc_extract_bits(card->cid, 0, 8), | 1578 | (int) card_extract_bits(card->cid, 0, 8), |
1579 | (int) mmc_extract_bits(card->cid, 8, 16)); | 1579 | (int) card_extract_bits(card->cid, 8, 16)); |
1580 | lcd_puts(0, line++, pbuf); | 1580 | lcd_puts(0, line++, pbuf); |
1581 | temp = mmc_extract_bits(card->csd, 2, 4); | 1581 | temp = card_extract_bits(card->csd, 2, 4); |
1582 | snprintf(pbuf, sizeof(pbuf), "MMC v%s", temp < 5 ? | 1582 | snprintf(pbuf, sizeof(pbuf), "MMC v%s", temp < 5 ? |
1583 | spec_vers[temp] : "?.?"); | 1583 | spec_vers[temp] : "?.?"); |
1584 | lcd_puts(0, line++, pbuf); | 1584 | lcd_puts(0, line++, pbuf); |
1585 | snprintf(pbuf, sizeof(pbuf), "Blocks: 0x%06lx", card->numblocks); | 1585 | snprintf(pbuf, sizeof(pbuf), "Blocks: 0x%06lx", card->numblocks); |
1586 | lcd_puts(0, line++, pbuf); | 1586 | lcd_puts(0, line++, pbuf); |
1587 | snprintf(pbuf, sizeof(pbuf), "Blksz.: %d P:%c%c", card->blocksize, | 1587 | snprintf(pbuf, sizeof(pbuf), "Blksz.: %d P:%c%c", card->blocksize, |
1588 | mmc_extract_bits(card->csd, 48, 1) ? 'R' : '-', | 1588 | card_extract_bits(card->csd, 48, 1) ? 'R' : '-', |
1589 | mmc_extract_bits(card->csd, 106, 1) ? 'W' : '-'); | 1589 | card_extract_bits(card->csd, 106, 1) ? 'W' : '-'); |
1590 | lcd_puts(0, line++, pbuf); | 1590 | lcd_puts(0, line++, pbuf); |
1591 | } | 1591 | } |
1592 | else /* Technical details */ | 1592 | else /* Technical details */ |
@@ -1606,12 +1606,12 @@ static bool dbg_mmc_info(void) | |||
1606 | snprintf(pbuf, sizeof(pbuf), "R2W: *%d", card->r2w_factor); | 1606 | snprintf(pbuf, sizeof(pbuf), "R2W: *%d", card->r2w_factor); |
1607 | lcd_puts(0, line++, pbuf); | 1607 | lcd_puts(0, line++, pbuf); |
1608 | snprintf(pbuf, sizeof(pbuf), "IRmax: %d..%d mA", | 1608 | snprintf(pbuf, sizeof(pbuf), "IRmax: %d..%d mA", |
1609 | i_vmin[mmc_extract_bits(card->csd, 66, 3)], | 1609 | i_vmin[card_extract_bits(card->csd, 66, 3)], |
1610 | i_vmax[mmc_extract_bits(card->csd, 69, 3)]); | 1610 | i_vmax[card_extract_bits(card->csd, 69, 3)]); |
1611 | lcd_puts(0, line++, pbuf); | 1611 | lcd_puts(0, line++, pbuf); |
1612 | snprintf(pbuf, sizeof(pbuf), "IWmax: %d..%d mA", | 1612 | snprintf(pbuf, sizeof(pbuf), "IWmax: %d..%d mA", |
1613 | i_vmin[mmc_extract_bits(card->csd, 72, 3)], | 1613 | i_vmin[card_extract_bits(card->csd, 72, 3)], |
1614 | i_vmax[mmc_extract_bits(card->csd, 75, 3)]); | 1614 | i_vmax[card_extract_bits(card->csd, 75, 3)]); |
1615 | lcd_puts(0, line++, pbuf); | 1615 | lcd_puts(0, line++, pbuf); |
1616 | } | 1616 | } |
1617 | } | 1617 | } |
@@ -1642,7 +1642,7 @@ static bool dbg_mmc_info(void) | |||
1642 | action_signalscreenchange(); | 1642 | action_signalscreenchange(); |
1643 | return false; | 1643 | return false; |
1644 | } | 1644 | } |
1645 | #else /* !HAVE_MMC */ | 1645 | #else /* !defined(HAVE_MMC) && !defined(HAVE_HOTSWAP) */ |
1646 | static bool dbg_disk_info(void) | 1646 | static bool dbg_disk_info(void) |
1647 | { | 1647 | { |
1648 | char buf[128]; | 1648 | char buf[128]; |
@@ -1799,7 +1799,7 @@ static bool dbg_disk_info(void) | |||
1799 | action_signalscreenchange(); | 1799 | action_signalscreenchange(); |
1800 | return false; | 1800 | return false; |
1801 | } | 1801 | } |
1802 | #endif /* !HAVE_MMC */ | 1802 | #endif /* !defined(HAVE_MMC) && !defined(HAVE_HOTSWAP) */ |
1803 | #endif /* !SIMULATOR */ | 1803 | #endif /* !SIMULATOR */ |
1804 | 1804 | ||
1805 | #ifdef HAVE_DIRCACHE | 1805 | #ifdef HAVE_DIRCACHE |
@@ -2278,8 +2278,10 @@ static const struct the_menu_item menuitems[] = { | |||
2278 | { "View partitions", dbg_partitions }, | 2278 | { "View partitions", dbg_partitions }, |
2279 | #endif | 2279 | #endif |
2280 | #ifndef SIMULATOR | 2280 | #ifndef SIMULATOR |
2281 | #ifdef HAVE_MMC | 2281 | #if defined(HAVE_MMC) |
2282 | { "View MMC info", dbg_mmc_info }, | 2282 | { "View MMC info", dbg_card_info }, |
2283 | #elif defined(HAVE_HOTSWAP) | ||
2284 | { "View microSD info", dbg_card_info }, | ||
2283 | #else | 2285 | #else |
2284 | { "View disk info", dbg_disk_info }, | 2286 | { "View disk info", dbg_disk_info }, |
2285 | #endif | 2287 | #endif |
diff --git a/apps/main.c b/apps/main.c index 3dfab06280..2dd90ef5fe 100644 --- a/apps/main.c +++ b/apps/main.c | |||
@@ -430,7 +430,8 @@ static void init(void) | |||
430 | /* enter USB mode early, before trying to mount */ | 430 | /* enter USB mode early, before trying to mount */ |
431 | if (button_get_w_tmo(HZ/10) == SYS_USB_CONNECTED) | 431 | if (button_get_w_tmo(HZ/10) == SYS_USB_CONNECTED) |
432 | #ifdef HAVE_MMC | 432 | #ifdef HAVE_MMC |
433 | if (!mmc_touched() || (mmc_remove_request() == SYS_MMC_EXTRACTED)) | 433 | if (!mmc_touched() || |
434 | (mmc_remove_request() == SYS_HOTSWAP_EXTRACTED)) | ||
434 | #endif | 435 | #endif |
435 | { | 436 | { |
436 | usb_screen(); | 437 | usb_screen(); |
diff --git a/apps/misc.c b/apps/misc.c index 88ec73e2d3..daa96b006a 100644 --- a/apps/misc.c +++ b/apps/misc.c | |||
@@ -828,7 +828,8 @@ long default_event_handler_ex(long event, void (*callback)(void *), void *parame | |||
828 | if (callback != NULL) | 828 | if (callback != NULL) |
829 | callback(parameter); | 829 | callback(parameter); |
830 | #ifdef HAVE_MMC | 830 | #ifdef HAVE_MMC |
831 | if (!mmc_touched() || (mmc_remove_request() == SYS_MMC_EXTRACTED)) | 831 | if (!mmc_touched() || |
832 | (mmc_remove_request() == SYS_HOTSWAP_EXTRACTED)) | ||
832 | #endif | 833 | #endif |
833 | { | 834 | { |
834 | scrobbler_flush_cache(); | 835 | scrobbler_flush_cache(); |
diff --git a/apps/screens.c b/apps/screens.c index d8e3121121..aebb7bd469 100644 --- a/apps/screens.c +++ b/apps/screens.c | |||
@@ -163,8 +163,8 @@ int mmc_remove_request(void) | |||
163 | queue_wait_w_tmo(&button_queue, &ev, HZ/2); | 163 | queue_wait_w_tmo(&button_queue, &ev, HZ/2); |
164 | switch (ev.id) | 164 | switch (ev.id) |
165 | { | 165 | { |
166 | case SYS_MMC_EXTRACTED: | 166 | case SYS_HOTSWAP_EXTRACTED: |
167 | return SYS_MMC_EXTRACTED; | 167 | return SYS_HOTSWAP_EXTRACTED; |
168 | 168 | ||
169 | case SYS_USB_DISCONNECTED: | 169 | case SYS_USB_DISCONNECTED: |
170 | return SYS_USB_DISCONNECTED; | 170 | return SYS_USB_DISCONNECTED; |
diff --git a/bootloader/main-pp.c b/bootloader/main-pp.c index 49d7f0a2f7..dd8b7984ca 100644 --- a/bootloader/main-pp.c +++ b/bootloader/main-pp.c | |||
@@ -352,7 +352,7 @@ int load_mi4_part(unsigned char* buf, struct partinfo* pinfo, | |||
352 | unsigned long sum; | 352 | unsigned long sum; |
353 | 353 | ||
354 | /* Read header to find out how long the mi4 file is. */ | 354 | /* Read header to find out how long the mi4 file is. */ |
355 | ata_read_sectors(pinfo->start + PPMI_SECTOR_OFFSET, | 355 | ata_read_sectors(IF_MV2(0,) pinfo->start + PPMI_SECTOR_OFFSET, |
356 | PPMI_SECTORS, &ppmi_header); | 356 | PPMI_SECTORS, &ppmi_header); |
357 | 357 | ||
358 | /* The first four characters at 0x80000 (sector 1024) should be PPMI*/ | 358 | /* The first four characters at 0x80000 (sector 1024) should be PPMI*/ |
@@ -362,7 +362,7 @@ int load_mi4_part(unsigned char* buf, struct partinfo* pinfo, | |||
362 | printf("BL mi4 size: %x", ppmi_header.length); | 362 | printf("BL mi4 size: %x", ppmi_header.length); |
363 | 363 | ||
364 | /* Read mi4 header of the OF */ | 364 | /* Read mi4 header of the OF */ |
365 | ata_read_sectors(pinfo->start + PPMI_SECTOR_OFFSET + PPMI_SECTORS | 365 | ata_read_sectors(IF_MV2(0,) pinfo->start + PPMI_SECTOR_OFFSET + PPMI_SECTORS |
366 | + (ppmi_header.length/512), MI4_HEADER_SECTORS, &mi4header); | 366 | + (ppmi_header.length/512), MI4_HEADER_SECTORS, &mi4header); |
367 | 367 | ||
368 | /* We don't support encrypted mi4 files yet */ | 368 | /* We don't support encrypted mi4 files yet */ |
@@ -385,7 +385,7 @@ int load_mi4_part(unsigned char* buf, struct partinfo* pinfo, | |||
385 | printf("Binary type: %.4s", mi4header.type); | 385 | printf("Binary type: %.4s", mi4header.type); |
386 | 386 | ||
387 | /* Load firmware */ | 387 | /* Load firmware */ |
388 | ata_read_sectors(pinfo->start + PPMI_SECTOR_OFFSET + PPMI_SECTORS | 388 | ata_read_sectors(IF_MV2(0,) pinfo->start + PPMI_SECTOR_OFFSET + PPMI_SECTORS |
389 | + (ppmi_header.length/512) + MI4_HEADER_SECTORS, | 389 | + (ppmi_header.length/512) + MI4_HEADER_SECTORS, |
390 | (mi4header.mi4size-MI4_HEADER_SIZE)/512, buf); | 390 | (mi4header.mi4size-MI4_HEADER_SIZE)/512, buf); |
391 | 391 | ||
@@ -404,7 +404,7 @@ int load_mi4_part(unsigned char* buf, struct partinfo* pinfo, | |||
404 | unsigned int i; | 404 | unsigned int i; |
405 | /* check which known version we have */ | 405 | /* check which known version we have */ |
406 | /* These are taken from the PPPS section, 0x00780240 */ | 406 | /* These are taken from the PPPS section, 0x00780240 */ |
407 | ata_read_sectors(pinfo->start + 0x3C01, 1, block); | 407 | ata_read_sectors(IF_MV2(0,) pinfo->start + 0x3C01, 1, block); |
408 | for (i=0; i<sizeof(OFDatabaseOffsets)/sizeof(*OFDatabaseOffsets); i++) | 408 | for (i=0; i<sizeof(OFDatabaseOffsets)/sizeof(*OFDatabaseOffsets); i++) |
409 | { | 409 | { |
410 | if (!memcmp(&block[0x40], OFDatabaseOffsets[i].version, | 410 | if (!memcmp(&block[0x40], OFDatabaseOffsets[i].version, |
@@ -417,9 +417,9 @@ int load_mi4_part(unsigned char* buf, struct partinfo* pinfo, | |||
417 | } | 417 | } |
418 | if (sector && offset) | 418 | if (sector && offset) |
419 | { | 419 | { |
420 | ata_read_sectors(sector, 1, block); | 420 | ata_read_sectors(IF_MV2(0,) sector, 1, block); |
421 | block[offset] = 0; | 421 | block[offset] = 0; |
422 | ata_write_sectors(sector, 1, block); | 422 | ata_write_sectors(IF_MV2(0,) sector, 1, block); |
423 | } | 423 | } |
424 | } | 424 | } |
425 | return EOK; | 425 | return EOK; |
@@ -428,12 +428,14 @@ int load_mi4_part(unsigned char* buf, struct partinfo* pinfo, | |||
428 | 428 | ||
429 | void* main(void) | 429 | void* main(void) |
430 | { | 430 | { |
431 | #ifndef SANSA_E200 | ||
431 | char buf[256]; | 432 | char buf[256]; |
433 | unsigned short* identify_info; | ||
434 | #endif | ||
432 | int i; | 435 | int i; |
433 | int btn; | 436 | int btn; |
434 | int rc; | 437 | int rc; |
435 | int num_partitions; | 438 | int num_partitions; |
436 | unsigned short* identify_info; | ||
437 | struct partinfo* pinfo; | 439 | struct partinfo* pinfo; |
438 | #ifdef SANSA_E200 | 440 | #ifdef SANSA_E200 |
439 | int usb_retry = 0; | 441 | int usb_retry = 0; |
@@ -475,6 +477,7 @@ void* main(void) | |||
475 | printf(MODEL_NAME); | 477 | printf(MODEL_NAME); |
476 | 478 | ||
477 | i=ata_init(); | 479 | i=ata_init(); |
480 | #ifndef SANSA_E200 | ||
478 | if (i==0) { | 481 | if (i==0) { |
479 | identify_info=ata_get_identify(); | 482 | identify_info=ata_get_identify(); |
480 | /* Show model */ | 483 | /* Show model */ |
@@ -489,8 +492,9 @@ void* main(void) | |||
489 | } else { | 492 | } else { |
490 | error(EATA, i); | 493 | error(EATA, i); |
491 | } | 494 | } |
495 | #endif | ||
492 | 496 | ||
493 | disk_init(); | 497 | disk_init(IF_MV(0)); |
494 | num_partitions = disk_mount_all(); | 498 | num_partitions = disk_mount_all(); |
495 | if (num_partitions<=0) | 499 | if (num_partitions<=0) |
496 | { | 500 | { |
diff --git a/firmware/SOURCES b/firmware/SOURCES index 28ef38e8db..2a7bea3e9f 100644 --- a/firmware/SOURCES +++ b/firmware/SOURCES | |||
@@ -116,6 +116,9 @@ drivers/ata.c | |||
116 | #endif /* HAVE_FLASH_DISK */ | 116 | #endif /* HAVE_FLASH_DISK */ |
117 | #endif /* HAVE_MMC */ | 117 | #endif /* HAVE_MMC */ |
118 | drivers/fat.c | 118 | drivers/fat.c |
119 | #ifdef HAVE_HOTSWAP | ||
120 | hotswap.c | ||
121 | #endif | ||
119 | #endif /* SIMULATOR */ | 122 | #endif /* SIMULATOR */ |
120 | 123 | ||
121 | /* EEPROM */ | 124 | /* EEPROM */ |
diff --git a/firmware/common/dir.c b/firmware/common/dir.c index bc44a53b70..0f46652b3c 100644 --- a/firmware/common/dir.c +++ b/firmware/common/dir.c | |||
@@ -37,6 +37,9 @@ static DIR opendirs[MAX_OPEN_DIRS]; | |||
37 | #ifdef HAVE_MMC | 37 | #ifdef HAVE_MMC |
38 | static const char* vol_names = "<MMC%d>"; | 38 | static const char* vol_names = "<MMC%d>"; |
39 | #define VOL_ENUM_POS 4 /* position of %d, to avoid runtime calculation */ | 39 | #define VOL_ENUM_POS 4 /* position of %d, to avoid runtime calculation */ |
40 | #elif defined(HAVE_HOTSWAP) | ||
41 | static const char* vol_names = "<microSD%d>"; | ||
42 | #define VOL_ENUM_POS 8 /* position of %d, to avoid runtime calculation */ | ||
40 | #else | 43 | #else |
41 | static const char* vol_names = "<HD%d>"; | 44 | static const char* vol_names = "<HD%d>"; |
42 | #define VOL_ENUM_POS 3 | 45 | #define VOL_ENUM_POS 3 |
diff --git a/firmware/common/disk.c b/firmware/common/disk.c index ebf8103aa0..f491c9b26a 100644 --- a/firmware/common/disk.c +++ b/firmware/common/disk.c | |||
@@ -20,8 +20,8 @@ | |||
20 | #include "ata.h" | 20 | #include "ata.h" |
21 | #include "debug.h" | 21 | #include "debug.h" |
22 | #include "fat.h" | 22 | #include "fat.h" |
23 | #ifdef HAVE_MMC | 23 | #ifdef HAVE_HOTSWAP |
24 | #include "ata_mmc.h" | 24 | #include "hotswap.h" |
25 | #endif | 25 | #endif |
26 | #include "file.h" /* for release_dirs() */ | 26 | #include "file.h" /* for release_dirs() */ |
27 | #include "dir.h" /* for release_files() */ | 27 | #include "dir.h" /* for release_files() */ |
@@ -101,8 +101,8 @@ int disk_mount_all(void) | |||
101 | int mounted; | 101 | int mounted; |
102 | int i; | 102 | int i; |
103 | 103 | ||
104 | #if defined(HAVE_MMC) && defined(HAVE_HOTSWAP) | 104 | #ifdef HAVE_MMC |
105 | mmc_enable_monitoring(false); | 105 | card_enable_monitoring(false); |
106 | #endif | 106 | #endif |
107 | 107 | ||
108 | fat_init(); /* reset all mounted partitions */ | 108 | fat_init(); /* reset all mounted partitions */ |
@@ -110,13 +110,13 @@ int disk_mount_all(void) | |||
110 | vol_drive[i] = -1; /* mark all as unassigned */ | 110 | vol_drive[i] = -1; /* mark all as unassigned */ |
111 | 111 | ||
112 | mounted = disk_mount(0); | 112 | mounted = disk_mount(0); |
113 | #ifdef HAVE_MMC | 113 | #ifdef HAVE_HOTSWAP |
114 | if (mmc_detect()) /* for Ondio, only if card detected */ | 114 | if (card_detect()) |
115 | { | 115 | { |
116 | mounted += disk_mount(1); /* try 2nd "drive", too */ | 116 | mounted += disk_mount(1); /* try 2nd "drive", too */ |
117 | } | 117 | } |
118 | #ifdef HAVE_HOTSWAP | 118 | #ifdef HAVE_MMC |
119 | mmc_enable_monitoring(true); | 119 | card_enable_monitoring(true); |
120 | #endif | 120 | #endif |
121 | #endif | 121 | #endif |
122 | 122 | ||
diff --git a/firmware/drivers/ata_mmc.c b/firmware/drivers/ata_mmc.c index 847e282e3b..66e60ead1d 100644 --- a/firmware/drivers/ata_mmc.c +++ b/firmware/drivers/ata_mmc.c | |||
@@ -397,26 +397,6 @@ static int receive_cxd(unsigned char *buf) | |||
397 | return 0; | 397 | return 0; |
398 | } | 398 | } |
399 | 399 | ||
400 | /* helper function to extract n (<=32) bits from an arbitrary position. | ||
401 | counting from MSB to LSB */ | ||
402 | unsigned long mmc_extract_bits( | ||
403 | const unsigned long *p, /* the start of the bitfield array */ | ||
404 | unsigned int start, /* bit no. to start reading */ | ||
405 | unsigned int size) /* how many bits to read */ | ||
406 | { | ||
407 | unsigned int long_index = start / 32; | ||
408 | unsigned int bit_index = start % 32; | ||
409 | unsigned long result; | ||
410 | |||
411 | result = p[long_index] << bit_index; | ||
412 | |||
413 | if (bit_index + size > 32) /* crossing longword boundary */ | ||
414 | result |= p[long_index+1] >> (32 - bit_index); | ||
415 | |||
416 | result >>= 32 - size; | ||
417 | |||
418 | return result; | ||
419 | } | ||
420 | 400 | ||
421 | static int initialize_card(int card_no) | 401 | static int initialize_card(int card_no) |
422 | { | 402 | { |
@@ -470,9 +450,9 @@ static int initialize_card(int card_no) | |||
470 | return rc * 10 - 6; | 450 | return rc * 10 - 6; |
471 | 451 | ||
472 | /* check block sizes */ | 452 | /* check block sizes */ |
473 | card->block_exp = mmc_extract_bits(card->csd, 44, 4); | 453 | card->block_exp = card_extract_bits(card->csd, 44, 4); |
474 | card->blocksize = 1 << card->block_exp; | 454 | card->blocksize = 1 << card->block_exp; |
475 | if ((mmc_extract_bits(card->csd, 102, 4) != card->block_exp) | 455 | if ((card_extract_bits(card->csd, 102, 4) != card->block_exp) |
476 | || card->blocksize > MAX_BLOCK_SIZE) | 456 | || card->blocksize > MAX_BLOCK_SIZE) |
477 | { | 457 | { |
478 | return -7; | 458 | return -7; |
@@ -486,16 +466,16 @@ static int initialize_card(int card_no) | |||
486 | } | 466 | } |
487 | 467 | ||
488 | /* max transmission speed, clock divider */ | 468 | /* max transmission speed, clock divider */ |
489 | temp = mmc_extract_bits(card->csd, 29, 3); | 469 | temp = card_extract_bits(card->csd, 29, 3); |
490 | temp = (temp > 3) ? 3 : temp; | 470 | temp = (temp > 3) ? 3 : temp; |
491 | card->speed = mantissa[mmc_extract_bits(card->csd, 25, 4)] | 471 | card->speed = mantissa[card_extract_bits(card->csd, 25, 4)] |
492 | * exponent[temp + 4]; | 472 | * exponent[temp + 4]; |
493 | card->bitrate_register = (FREQ/4-1) / card->speed; | 473 | card->bitrate_register = (FREQ/4-1) / card->speed; |
494 | 474 | ||
495 | /* NSAC, TSAC, read timeout */ | 475 | /* NSAC, TSAC, read timeout */ |
496 | card->nsac = 100 * mmc_extract_bits(card->csd, 16, 8); | 476 | card->nsac = 100 * card_extract_bits(card->csd, 16, 8); |
497 | card->tsac = mantissa[mmc_extract_bits(card->csd, 9, 4)]; | 477 | card->tsac = mantissa[card_extract_bits(card->csd, 9, 4)]; |
498 | temp = mmc_extract_bits(card->csd, 13, 3); | 478 | temp = card_extract_bits(card->csd, 13, 3); |
499 | card->read_timeout = ((FREQ/4) / (card->bitrate_register + 1) | 479 | card->read_timeout = ((FREQ/4) / (card->bitrate_register + 1) |
500 | * card->tsac / exponent[9 - temp] | 480 | * card->tsac / exponent[9 - temp] |
501 | + (10 * card->nsac)); | 481 | + (10 * card->nsac)); |
@@ -503,7 +483,7 @@ static int initialize_card(int card_no) | |||
503 | card->tsac = card->tsac * exponent[temp] / 10; | 483 | card->tsac = card->tsac * exponent[temp] / 10; |
504 | 484 | ||
505 | /* r2w_factor, write timeout */ | 485 | /* r2w_factor, write timeout */ |
506 | card->r2w_factor = 1 << mmc_extract_bits(card->csd, 99, 3); | 486 | card->r2w_factor = 1 << card_extract_bits(card->csd, 99, 3); |
507 | if (card->r2w_factor > 32) /* dirty MMC spec violation */ | 487 | if (card->r2w_factor > 32) /* dirty MMC spec violation */ |
508 | { | 488 | { |
509 | card->read_timeout *= 4; /* add safety factor */ | 489 | card->read_timeout *= 4; /* add safety factor */ |
@@ -513,8 +493,8 @@ static int initialize_card(int card_no) | |||
513 | card->write_timeout = card->read_timeout * card->r2w_factor; | 493 | card->write_timeout = card->read_timeout * card->r2w_factor; |
514 | 494 | ||
515 | /* card size */ | 495 | /* card size */ |
516 | card->numblocks = (mmc_extract_bits(card->csd, 54, 12) + 1) | 496 | card->numblocks = (card_extract_bits(card->csd, 54, 12) + 1) |
517 | * (1 << (mmc_extract_bits(card->csd, 78, 3) + 2)); | 497 | * (1 << (card_extract_bits(card->csd, 78, 3) + 2)); |
518 | card->size = card->numblocks * card->blocksize; | 498 | card->size = card->numblocks * card->blocksize; |
519 | 499 | ||
520 | /* switch to full speed */ | 500 | /* switch to full speed */ |
@@ -993,12 +973,12 @@ static void mmc_thread(void) | |||
993 | break; | 973 | break; |
994 | 974 | ||
995 | #ifdef HAVE_HOTSWAP | 975 | #ifdef HAVE_HOTSWAP |
996 | case SYS_MMC_INSERTED: | 976 | case SYS_HOTSWAP_INSERTED: |
997 | disk_mount(1); /* mount MMC */ | 977 | disk_mount(1); /* mount MMC */ |
998 | queue_broadcast(SYS_FS_CHANGED, 0); | 978 | queue_broadcast(SYS_FS_CHANGED, 0); |
999 | break; | 979 | break; |
1000 | 980 | ||
1001 | case SYS_MMC_EXTRACTED: | 981 | case SYS_HOTSWAP_EXTRACTED: |
1002 | disk_unmount(1); /* release "by force" */ | 982 | disk_unmount(1); /* release "by force" */ |
1003 | queue_broadcast(SYS_FS_CHANGED, 0); | 983 | queue_broadcast(SYS_FS_CHANGED, 0); |
1004 | break; | 984 | break; |
@@ -1097,11 +1077,11 @@ static void mmc_tick(void) | |||
1097 | { | 1077 | { |
1098 | if (current_status) | 1078 | if (current_status) |
1099 | { | 1079 | { |
1100 | queue_broadcast(SYS_MMC_INSERTED, 0); | 1080 | queue_broadcast(SYS_HOTSWAP_INSERTED, 0); |
1101 | } | 1081 | } |
1102 | else | 1082 | else |
1103 | { | 1083 | { |
1104 | queue_broadcast(SYS_MMC_EXTRACTED, 0); | 1084 | queue_broadcast(SYS_HOTSWAP_EXTRACTED, 0); |
1105 | mmc_status = MMC_UNTOUCHED; | 1085 | mmc_status = MMC_UNTOUCHED; |
1106 | card_info[1].initialized = false; | 1086 | card_info[1].initialized = false; |
1107 | } | 1087 | } |
diff --git a/firmware/export/ata_mmc.h b/firmware/export/ata_mmc.h index a4e9f71f09..2361c439b5 100644 --- a/firmware/export/ata_mmc.h +++ b/firmware/export/ata_mmc.h | |||
@@ -18,34 +18,14 @@ | |||
18 | ****************************************************************************/ | 18 | ****************************************************************************/ |
19 | #ifndef __ATA_MMC_H__ | 19 | #ifndef __ATA_MMC_H__ |
20 | #define __ATA_MMC_H__ | 20 | #define __ATA_MMC_H__ |
21 | 21 | #include "hotswap.h" | |
22 | typedef struct | ||
23 | { | ||
24 | bool initialized; | ||
25 | unsigned char bitrate_register; | ||
26 | unsigned long read_timeout; /* n * 8 clock cycles */ | ||
27 | unsigned long write_timeout; /* n * 8 clock cycles */ | ||
28 | |||
29 | unsigned long ocr; /* OCR register */ | ||
30 | unsigned long csd[4]; /* CSD register, 16 bytes */ | ||
31 | unsigned long cid[4]; /* CID register, 16 bytes */ | ||
32 | unsigned long speed; /* bit/s */ | ||
33 | unsigned int nsac; /* clock cycles */ | ||
34 | unsigned long tsac; /* n * 0.1 ns */ | ||
35 | unsigned int r2w_factor; | ||
36 | unsigned long size; /* size in bytes */ | ||
37 | unsigned long numblocks; /* size in flash blocks */ | ||
38 | unsigned int blocksize; /* block size in bytes */ | ||
39 | unsigned int block_exp; /* block size exponent */ | ||
40 | } tCardInfo; | ||
41 | 22 | ||
42 | void mmc_enable_int_flash_clock(bool on); | 23 | void mmc_enable_int_flash_clock(bool on); |
43 | bool mmc_detect(void); | 24 | bool mmc_detect(void); |
44 | unsigned long mmc_extract_bits(const unsigned long *p, unsigned int start, | ||
45 | unsigned int size); | ||
46 | tCardInfo *mmc_card_info(int card_no); | 25 | tCardInfo *mmc_card_info(int card_no); |
47 | bool mmc_touched(void); | 26 | bool mmc_touched(void); |
48 | bool mmc_usb_active(int delayticks); | 27 | bool mmc_usb_active(int delayticks); |
28 | |||
49 | #ifdef HAVE_HOTSWAP | 29 | #ifdef HAVE_HOTSWAP |
50 | void mmc_enable_monitoring(bool on); | 30 | void mmc_enable_monitoring(bool on); |
51 | #endif | 31 | #endif |
diff --git a/firmware/export/config-e200.h b/firmware/export/config-e200.h index 71b1270749..f9708697dc 100644 --- a/firmware/export/config-e200.h +++ b/firmware/export/config-e200.h | |||
@@ -33,6 +33,11 @@ | |||
33 | /* define this if you have LCD enable function */ | 33 | /* define this if you have LCD enable function */ |
34 | #define HAVE_LCD_ENABLE | 34 | #define HAVE_LCD_ENABLE |
35 | 35 | ||
36 | #ifndef SIMULATOR | ||
37 | #define HAVE_HOTSWAP | ||
38 | #define HAVE_MULTIVOLUME | ||
39 | #endif | ||
40 | |||
36 | #define HAVE_BACKLIGHT_BRIGHTNESS | 41 | #define HAVE_BACKLIGHT_BRIGHTNESS |
37 | /* Main LCD backlight brightness range and defaults */ | 42 | /* Main LCD backlight brightness range and defaults */ |
38 | #define MIN_BRIGHTNESS_SETTING 1 | 43 | #define MIN_BRIGHTNESS_SETTING 1 |
diff --git a/firmware/export/config.h b/firmware/export/config.h index 4652359e62..ffcbf688ea 100644 --- a/firmware/export/config.h +++ b/firmware/export/config.h | |||
@@ -247,7 +247,7 @@ | |||
247 | /* Enable the directory cache and tagcache in RAM if we have | 247 | /* Enable the directory cache and tagcache in RAM if we have |
248 | * plenty of RAM. Both features can be enabled independently. */ | 248 | * plenty of RAM. Both features can be enabled independently. */ |
249 | #if ((defined(MEMORYSIZE) && (MEMORYSIZE > 8)) || MEM > 8) && \ | 249 | #if ((defined(MEMORYSIZE) && (MEMORYSIZE > 8)) || MEM > 8) && \ |
250 | !defined(BOOTLOADER) | 250 | !defined(BOOTLOADER) && !defined(SANSA_E200) |
251 | #define HAVE_DIRCACHE | 251 | #define HAVE_DIRCACHE |
252 | #ifdef HAVE_TAGCACHE | 252 | #ifdef HAVE_TAGCACHE |
253 | #define HAVE_TC_RAMCACHE | 253 | #define HAVE_TC_RAMCACHE |
diff --git a/firmware/export/hotswap.h b/firmware/export/hotswap.h new file mode 100644 index 0000000000..c6a657d731 --- /dev/null +++ b/firmware/export/hotswap.h | |||
@@ -0,0 +1,59 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2004 by Jens Arnold | ||
11 | * | ||
12 | * All files in this archive are subject to the GNU General Public License. | ||
13 | * See the file COPYING in the source tree root for full license agreement. | ||
14 | * | ||
15 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
16 | * KIND, either express or implied. | ||
17 | * | ||
18 | ****************************************************************************/ | ||
19 | #ifndef __HOTSWAP_H__ | ||
20 | #define __HOTSWAP_H__ | ||
21 | |||
22 | typedef struct | ||
23 | { | ||
24 | bool initialized; | ||
25 | unsigned char bitrate_register; | ||
26 | unsigned long read_timeout; /* n * 8 clock cycles */ | ||
27 | unsigned long write_timeout; /* n * 8 clock cycles */ | ||
28 | |||
29 | unsigned long ocr; /* OCR register */ | ||
30 | unsigned long csd[4]; /* CSD register, 16 bytes */ | ||
31 | unsigned long cid[4]; /* CID register, 16 bytes */ | ||
32 | unsigned long speed; /* bit/s */ | ||
33 | unsigned int nsac; /* clock cycles */ | ||
34 | unsigned long tsac; /* n * 0.1 ns */ | ||
35 | unsigned int r2w_factor; | ||
36 | unsigned long size; /* size in bytes */ | ||
37 | unsigned long numblocks; /* size in flash blocks */ | ||
38 | unsigned int blocksize; /* block size in bytes */ | ||
39 | unsigned int block_exp; /* block size exponent */ | ||
40 | } tCardInfo; | ||
41 | |||
42 | #ifdef TARGET_TREE | ||
43 | bool card_detect(void); | ||
44 | tCardInfo *card_get_info(int card_no); | ||
45 | #else /* HAVE_MMC */ | ||
46 | #include "ata_mmc.h" | ||
47 | #define card_detect mmc_detect | ||
48 | #define card_get_info mmc_card_info | ||
49 | #define card_touched mmc_touched | ||
50 | #define card_enable_monitoring mmc_enable_monitoring | ||
51 | #endif | ||
52 | |||
53 | /* helper function to extract n (<=32) bits from an arbitrary position. | ||
54 | counting from MSB to LSB */ | ||
55 | unsigned long card_extract_bits( | ||
56 | const unsigned long *p, /* the start of the bitfield array */ | ||
57 | unsigned int start, /* bit no. to start reading */ | ||
58 | unsigned int size); /* how many bits to read */ | ||
59 | #endif | ||
diff --git a/firmware/export/kernel.h b/firmware/export/kernel.h index 9e3a8d25df..d5898a97f1 100644 --- a/firmware/export/kernel.h +++ b/firmware/export/kernel.h | |||
@@ -41,8 +41,8 @@ | |||
41 | #define SYS_USB_DISCONNECTED ((SYS_EVENT | ((long)3 << 27))) | 41 | #define SYS_USB_DISCONNECTED ((SYS_EVENT | ((long)3 << 27))) |
42 | #define SYS_USB_DISCONNECTED_ACK ((SYS_EVENT | ((long)4 << 27))) | 42 | #define SYS_USB_DISCONNECTED_ACK ((SYS_EVENT | ((long)4 << 27))) |
43 | #define SYS_TIMEOUT ((SYS_EVENT | ((long)5 << 27))) | 43 | #define SYS_TIMEOUT ((SYS_EVENT | ((long)5 << 27))) |
44 | #define SYS_MMC_INSERTED ((SYS_EVENT | ((long)6 << 27))) | 44 | #define SYS_HOTSWAP_INSERTED ((SYS_EVENT | ((long)6 << 27))) |
45 | #define SYS_MMC_EXTRACTED ((SYS_EVENT | ((long)7 << 27))) | 45 | #define SYS_HOTSWAP_EXTRACTED ((SYS_EVENT | ((long)7 << 27))) |
46 | #define SYS_POWEROFF ((SYS_EVENT | ((long)8 << 27))) | 46 | #define SYS_POWEROFF ((SYS_EVENT | ((long)8 << 27))) |
47 | #define SYS_FS_CHANGED ((SYS_EVENT | ((long)9 << 27))) | 47 | #define SYS_FS_CHANGED ((SYS_EVENT | ((long)9 << 27))) |
48 | #define SYS_CHARGER_CONNECTED ((SYS_EVENT | ((long)10 << 27))) | 48 | #define SYS_CHARGER_CONNECTED ((SYS_EVENT | ((long)10 << 27))) |
diff --git a/firmware/export/pp5024.h b/firmware/export/pp5024.h index e7758b9ce5..5e2de17741 100644 --- a/firmware/export/pp5024.h +++ b/firmware/export/pp5024.h | |||
@@ -24,7 +24,7 @@ | |||
24 | #include "pp5020.h" | 24 | #include "pp5020.h" |
25 | 25 | ||
26 | #undef GPIO_IRQ | 26 | #undef GPIO_IRQ |
27 | /* Ports A, ?? */ | 27 | /* Ports A, B, ?? */ |
28 | #define GPIO0_IRQ (32+0) | 28 | #define GPIO0_IRQ (32+0) |
29 | /* Ports F, H, ?? */ | 29 | /* Ports F, H, ?? */ |
30 | #define GPIO1_IRQ (32+1) | 30 | #define GPIO1_IRQ (32+1) |
diff --git a/firmware/hotswap.c b/firmware/hotswap.c new file mode 100644 index 0000000000..5620edf10b --- /dev/null +++ b/firmware/hotswap.c | |||
@@ -0,0 +1,58 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2004 by Jens Arnold | ||
11 | * | ||
12 | * All files in this archive are subject to the GNU General Public License. | ||
13 | * See the file COPYING in the source tree root for full license agreement. | ||
14 | * | ||
15 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
16 | * KIND, either express or implied. | ||
17 | * | ||
18 | ****************************************************************************/ | ||
19 | #include <stdbool.h> | ||
20 | #include "config.h" | ||
21 | #ifdef TARGET_TREE | ||
22 | #include "hotswap-target.h" | ||
23 | #else | ||
24 | #include "ata_mmc.h" | ||
25 | #endif | ||
26 | |||
27 | /* helper function to extract n (<=32) bits from an arbitrary position. | ||
28 | counting from MSB to LSB */ | ||
29 | unsigned long card_extract_bits( | ||
30 | const unsigned long *p, /* the start of the bitfield array */ | ||
31 | unsigned int start, /* bit no. to start reading */ | ||
32 | unsigned int size) /* how many bits to read */ | ||
33 | { | ||
34 | unsigned int long_index = start / 32; | ||
35 | unsigned int bit_index = start % 32; | ||
36 | unsigned long result; | ||
37 | |||
38 | result = p[long_index] << bit_index; | ||
39 | |||
40 | if (bit_index + size > 32) /* crossing longword boundary */ | ||
41 | result |= p[long_index+1] >> (32 - bit_index); | ||
42 | |||
43 | result >>= 32 - size; | ||
44 | |||
45 | return result; | ||
46 | } | ||
47 | |||
48 | #ifdef TARGET_TREE | ||
49 | bool card_detect(void) | ||
50 | { | ||
51 | return card_detect_target(); | ||
52 | } | ||
53 | |||
54 | tCardInfo *card_get_info(int card_no) | ||
55 | { | ||
56 | return card_get_info_target(card_no); | ||
57 | } | ||
58 | #endif | ||
diff --git a/firmware/include/dir.h b/firmware/include/dir.h index c354082bec..020b24a502 100644 --- a/firmware/include/dir.h +++ b/firmware/include/dir.h | |||
@@ -71,6 +71,10 @@ typedef struct { | |||
71 | #endif | 71 | #endif |
72 | } DIR; | 72 | } DIR; |
73 | 73 | ||
74 | #ifdef HAVE_HOTSWAP | ||
75 | char *get_volume_name(int volume); | ||
76 | #endif | ||
77 | |||
74 | #ifndef DIRFUNCTIONS_DEFINED | 78 | #ifndef DIRFUNCTIONS_DEFINED |
75 | 79 | ||
76 | extern DIR* opendir(const char* name); | 80 | extern DIR* opendir(const char* name); |
diff --git a/firmware/target/arm/sandisk/sansa-e200/ata-e200.c b/firmware/target/arm/sandisk/sansa-e200/ata-e200.c index 8eccdfb729..fea6773ac9 100644 --- a/firmware/target/arm/sandisk/sansa-e200/ata-e200.c +++ b/firmware/target/arm/sandisk/sansa-e200/ata-e200.c | |||
@@ -17,14 +17,16 @@ | |||
17 | * | 17 | * |
18 | ****************************************************************************/ | 18 | ****************************************************************************/ |
19 | #include "ata.h" | 19 | #include "ata.h" |
20 | #include "hotswap-target.h" | ||
20 | #include "ata-target.h" | 21 | #include "ata-target.h" |
21 | #include "ata_idle_notify.h" | 22 | #include "ata_idle_notify.h" |
22 | #include "system.h" | 23 | #include "system.h" |
23 | #include <string.h> | 24 | #include <string.h> |
24 | #include "thread.h" | 25 | #include "thread.h" |
26 | #include "led.h" | ||
27 | #include "disk.h" | ||
25 | #include "pp5024.h" | 28 | #include "pp5024.h" |
26 | 29 | #include "panic.h" | |
27 | #define NOINLINE_ATTR __attribute__((noinline)) /* don't inline the loops */ | ||
28 | 30 | ||
29 | #define BLOCK_SIZE (512) | 31 | #define BLOCK_SIZE (512) |
30 | #define SECTOR_SIZE (512) | 32 | #define SECTOR_SIZE (512) |
@@ -48,6 +50,7 @@ | |||
48 | #define DATA_DONE (1 << 12) | 50 | #define DATA_DONE (1 << 12) |
49 | #define CMD_DONE (1 << 13) | 51 | #define CMD_DONE (1 << 13) |
50 | #define ERROR_BITS (0x3f) | 52 | #define ERROR_BITS (0x3f) |
53 | #define READY_FOR_DATA (1 << 8) | ||
51 | #define FIFO_FULL (1 << 7) | 54 | #define FIFO_FULL (1 << 7) |
52 | #define FIFO_EMPTY (1 << 6) | 55 | #define FIFO_EMPTY (1 << 6) |
53 | 56 | ||
@@ -65,370 +68,481 @@ | |||
65 | #define FIFO_SIZE 16 /* FIFO is 16 words deep */ | 68 | #define FIFO_SIZE 16 /* FIFO is 16 words deep */ |
66 | 69 | ||
67 | /* SD Commands */ | 70 | /* SD Commands */ |
68 | #define GO_IDLE_STATE 0 | 71 | #define GO_IDLE_STATE 0 |
69 | #define ALL_SEND_CID 2 | 72 | #define ALL_SEND_CID 2 |
70 | #define SEND_RELATIVE_ADDR 3 | 73 | #define SEND_RELATIVE_ADDR 3 |
71 | #define SET_DSR 4 | 74 | #define SET_DSR 4 |
72 | #define SWITCH_FUNC 6 | 75 | #define SWITCH_FUNC 6 |
73 | #define SELECT_CARD 7 | 76 | #define SELECT_CARD 7 |
74 | #define DESELECT_CARD 7 | 77 | #define DESELECT_CARD 7 |
75 | #define SEND_CSD 9 | 78 | #define SEND_CSD 9 |
76 | #define SEND_CID 10 | 79 | #define SEND_CID 10 |
77 | #define STOP_TRANSMISSION 12 | 80 | #define STOP_TRANSMISSION 12 |
78 | #define SEND_STATUS 13 | 81 | #define SEND_STATUS 13 |
79 | #define GO_INACTIVE_STATE 15 | 82 | #define GO_INACTIVE_STATE 15 |
80 | #define SET_BLOCKLEN 16 | 83 | #define SET_BLOCKLEN 16 |
81 | #define READ_SINGLE_BLOCK 17 | 84 | #define READ_SINGLE_BLOCK 17 |
82 | #define READ_MULTIPLE_BLOCK 18 | 85 | #define READ_MULTIPLE_BLOCK 18 |
83 | #define WRITE_BLOCK 24 | 86 | #define SEND_NUM_WR_BLOCKS 22 |
84 | #define WRITE_MULTIPLE_BLOCK 25 | 87 | #define WRITE_BLOCK 24 |
85 | #define ERASE_WR_BLK_START 32 | 88 | #define WRITE_MULTIPLE_BLOCK 25 |
86 | #define ERASE_WR_BLK_END 33 | 89 | #define ERASE_WR_BLK_START 32 |
87 | #define ERASE 38 | 90 | #define ERASE_WR_BLK_END 33 |
91 | #define ERASE 38 | ||
92 | #define APP_CMD 55 | ||
93 | |||
94 | #define EC_POWER_UP 1 /* error code */ | ||
95 | #define EC_READ_TIMEOUT 2 /* error code */ | ||
96 | #define EC_WRITE_TIMEOUT 3 /* error code */ | ||
97 | #define EC_TRAN_SEL_BANK 4 /* error code */ | ||
98 | #define EC_TRAN_READ_ENTRY 5 /* error code */ | ||
99 | #define EC_TRAN_READ_EXIT 6 /* error code */ | ||
100 | #define EC_TRAN_WRITE_ENTRY 7 /* error code */ | ||
101 | #define EC_TRAN_WRITE_EXIT 8 /* error code */ | ||
102 | #define DO_PANIC 32 /* marker */ | ||
103 | #define NO_PANIC 0 /* marker */ | ||
104 | #define EC_COMMAND 10 /* error code */ | ||
105 | #define EC_FIFO_SEL_BANK_EMPTY 11 /* error code */ | ||
106 | #define EC_FIFO_SEL_BANK_DONE 12 /* error code */ | ||
107 | #define EC_FIFO_ENA_BANK_EMPTY 13 /* error code */ | ||
108 | #define EC_FIFO_READ_FULL 14 /* error code */ | ||
109 | #define EC_FIFO_WR_EMPTY 15 /* error code */ | ||
110 | #define EC_FIFO_WR_DONE 16 /* error code */ | ||
88 | 111 | ||
89 | /* Application Specific commands */ | 112 | /* Application Specific commands */ |
90 | #define SET_BUS_WIDTH 6 | 113 | #define SET_BUS_WIDTH 6 |
91 | #define SD_APP_OP_COND 41 | 114 | #define SD_APP_OP_COND 41 |
92 | 115 | ||
93 | #define READ_TIMEOUT 5*HZ | 116 | /* for compatibility */ |
94 | #define WRITE_TIMEOUT 0.5*HZ | ||
95 | |||
96 | static unsigned short identify_info[SECTOR_SIZE]; | ||
97 | int ata_spinup_time = 0; | 117 | int ata_spinup_time = 0; |
118 | |||
98 | long last_disk_activity = -1; | 119 | long last_disk_activity = -1; |
99 | static bool initialized = false; | ||
100 | 120 | ||
101 | static unsigned char current_bank = 0; /* The bank that we are working with */ | 121 | static bool initialized = false; |
122 | static int sd1_status = 0x00; /* 0x00:inserted, 0x80:not inserted */ | ||
102 | 123 | ||
103 | static tSDCardInfo card_info[2]; | 124 | static tSDCardInfo card_info[2]; |
125 | static tSDCardInfo *currcard; /* current active card */ | ||
104 | 126 | ||
105 | /* For multi volume support */ | 127 | /* Shoot for around 75% usage */ |
106 | static int current_card = 0; | 128 | static long sd_stack [(DEFAULT_STACK_SIZE*2 + 0x1c0)/sizeof(long)]; |
107 | 129 | static const char sd_thread_name[] = "ata/sd"; | |
108 | static struct mutex sd_mtx; | 130 | static struct mutex sd_mtx; |
109 | |||
110 | static long sd_stack [(DEFAULT_STACK_SIZE*2 + 0x800)/sizeof(long)]; | ||
111 | |||
112 | static const char sd_thread_name[] = "sd"; | ||
113 | static struct event_queue sd_queue; | 131 | static struct event_queue sd_queue; |
114 | 132 | ||
133 | /* Posted when card plugged status has changed */ | ||
134 | #define SD_HOTSWAP 1 | ||
115 | 135 | ||
116 | /* Private Functions */ | 136 | /* Private Functions */ |
117 | 137 | ||
118 | bool sd_send_command(unsigned int cmd, unsigned long arg1, unsigned int arg2) | 138 | static unsigned int check_time[10]; |
139 | |||
140 | static inline void sd_check_timeout(unsigned int timeout, int id) | ||
119 | { | 141 | { |
120 | bool result = false; | 142 | if (USEC_TIMER > check_time[id] + timeout) |
121 | do | 143 | panicf("Error SDCard: %d", id); |
144 | } | ||
145 | |||
146 | static inline bool sd_poll_status(unsigned int trigger, unsigned int timeout, | ||
147 | int id) | ||
148 | { | ||
149 | unsigned int t = USEC_TIMER; | ||
150 | |||
151 | while ((STATUS_REG & trigger) == 0) | ||
122 | { | 152 | { |
123 | CMD_REG0 = cmd; | 153 | if (USEC_TIMER > t + timeout) |
124 | CMD_REG1 = (unsigned int)((arg1 & 0xffff0000) >> 16); | ||
125 | CMD_REG2 = (unsigned int)((arg1 & 0xffff)); | ||
126 | UNKNOWN = arg2; | ||
127 | while ((STATUS_REG & CMD_DONE) == 0) | ||
128 | { | 154 | { |
129 | /* Busy wait */ | 155 | if(id & DO_PANIC) |
156 | panicf("Error SDCard: %d", id & 31); | ||
157 | |||
158 | return false; | ||
130 | } | 159 | } |
131 | if ((STATUS_REG & ERROR_BITS) == 0) | 160 | } |
132 | { | 161 | |
133 | result = true; | 162 | return true; |
134 | } | ||
135 | } while ((STATUS_REG & ERROR_BITS) != 0); | ||
136 | return result; | ||
137 | } | 163 | } |
138 | 164 | ||
139 | void sd_read_response(unsigned int *response, int type) | 165 | static bool sd_command(unsigned int cmd, unsigned long arg1, |
166 | unsigned int *response, unsigned int type) | ||
140 | { | 167 | { |
141 | int i; | 168 | int i, words; /* Number of 16 bit words to read from RESPONSE_REG */ |
142 | int words; /* Number of 16 bit words to read from RESPONSE_REG */ | 169 | unsigned int data[9]; |
143 | unsigned int response_from_card[9]; | 170 | |
144 | if(type == 2) | 171 | while (1) |
145 | { | 172 | { |
146 | words = 9; /* R2 types are 8.5 16-bit words long */ | 173 | CMD_REG0 = cmd; |
147 | } else { | 174 | CMD_REG1 = (unsigned int)((arg1 & 0xffff0000) >> 16); |
148 | words = 3; | 175 | CMD_REG2 = (unsigned int)((arg1 & 0xffff)); |
176 | UNKNOWN = type; | ||
177 | |||
178 | sd_poll_status(CMD_DONE, 100000, EC_COMMAND | DO_PANIC); | ||
179 | |||
180 | if ((STATUS_REG & ERROR_BITS) == 0) | ||
181 | break; | ||
182 | |||
183 | priority_yield(); | ||
149 | } | 184 | } |
150 | 185 | ||
186 | if (cmd == GO_IDLE_STATE) return true; /* no response here */ | ||
187 | |||
188 | words = (type == 2) ? 9 : 3; | ||
189 | |||
151 | for (i = 0; i < words; i++) /* RESPONSE_REG is read MSB first */ | 190 | for (i = 0; i < words; i++) /* RESPONSE_REG is read MSB first */ |
152 | { | 191 | { |
153 | response_from_card[i] = RESPONSE_REG; /* Read most significant 16-bit word */ | 192 | data[i] = RESPONSE_REG; /* Read most significant 16-bit word */ |
154 | } | 193 | } |
155 | 194 | ||
156 | switch (type) | 195 | if (type == 2) |
157 | { | 196 | { |
158 | case 1: | 197 | /* Response type 2 has the following structure: |
159 | /* Response type 1 has the following structure: | 198 | * [135:135] Start Bit - '0' |
160 | Start bit | 199 | * [134:134] Transmission bit - '0' |
161 | Transmission bit | 200 | * [133:128] Reserved - '111111' |
162 | Command index (6 bits) | 201 | * [127:001] CID or CSD register including internal CRC7 |
163 | Card Status (32 bits) | 202 | * [000:000] End Bit - '1' |
164 | CRC7 (7 bits) | 203 | */ |
165 | Stop bit | 204 | response[3] = (data[0]<<24) + (data[1]<<8) + ((data[2]&0xff00)>>8); |
166 | */ | 205 | response[2] = (data[2]<<24) + (data[3]<<8) + ((data[4]&0xff00)>>8); |
167 | /* TODO: Sanity checks */ | 206 | response[1] = (data[4]<<24) + (data[5]<<8) + ((data[6]&0xff00)>>8); |
168 | response[0] = ((response_from_card[0] & 0xff) << 24) | 207 | response[0] = (data[6]<<24) + (data[7]<<8) + ((data[8]&0xff00)>>8); |
169 | + (response_from_card[1] << 8) | 208 | } |
170 | + ((response_from_card[2] & 0xff00) >> 8); | 209 | else |
171 | break; | 210 | { |
172 | case 2: | 211 | /* Response types 1, 1b, 3, 6 have the following structure: |
173 | /* Response type 2 has the following structure: | 212 | * Types 4 and 5 are not supported. |
174 | Start bit | 213 | * |
175 | Transmission bit | 214 | * [47] Start bit - '0' |
176 | Reserved (6 bits) | 215 | * [46] Transmission bit - '0' |
177 | CSD/CID register (127 bits) | 216 | * [45:40] R1, R1b, R6: Command index |
178 | Stop bit | 217 | * R3: Reserved - '111111' |
179 | */ | 218 | * [39:8] R1, R1b: Card Status |
180 | response[3] = ((response_from_card[0]&0xff)<<24) + | 219 | * R3: OCR Register |
181 | (response_from_card[1]<<8) + | 220 | * R6: [31:16] RCA |
182 | ((response_from_card[2]&0xff00)>>8); | 221 | * [15: 0] Card Status Bits 23, 22, 19, 12:0 |
183 | response[2] = ((response_from_card[2]&0xff)<<24) + | 222 | * [23] COM_CRC_ERROR |
184 | (response_from_card[3]<<8) + | 223 | * [22] ILLEGAL_COMMAND |
185 | ((response_from_card[4]&0xff00)>>8); | 224 | * [19] ERROR |
186 | response[1] = ((response_from_card[4]&0xff)<<24) + | 225 | * [12:9] CURRENT_STATE |
187 | (response_from_card[5]<<8) + | 226 | * [8] READY_FOR_DATA |
188 | ((response_from_card[6]&0xff00)>>8); | 227 | * [7:6] |
189 | response[0] = ((response_from_card[6]&0xff)<<24) + | 228 | * [5] APP_CMD |
190 | (response_from_card[7]<<8) + | 229 | * [4] |
191 | ((response_from_card[8]&0xff00)>>8); | 230 | * [3] AKE_SEQ_ERROR |
192 | break; | 231 | * [2] Reserved |
193 | case 3: | 232 | * [1:0] Reserved for test mode |
194 | /* Response type 3 has the following structure: | 233 | * [7:1] R1, R1b: CRC7 |
195 | Start bit | 234 | * R3: Reserved - '1111111' |
196 | Transmission bit | 235 | * [0] End Bit - '1' |
197 | Reserved (6 bits) | 236 | */ |
198 | OCR register (32 bits) | 237 | response[0] = (data[0]<<24) + (data[1]<<8) + ((data[2]&0xff00)>>8); |
199 | Reserved (7 bits) | ||
200 | Stop bit | ||
201 | */ | ||
202 | response[0] = ((response_from_card[0] & 0xff) << 24) | ||
203 | + (response_from_card[1] << 8) | ||
204 | + ((response_from_card[2] & 0xff00) >> 8); | ||
205 | /* Types 4-6 not supported yet */ | ||
206 | } | 238 | } |
207 | } | ||
208 | 239 | ||
209 | bool sd_send_acommand(unsigned int cmd, unsigned long arg1, unsigned int arg2) | ||
210 | { | ||
211 | unsigned int returncode; | ||
212 | if (sd_send_command(55, (card_info[current_card].rca)<<16, 1) == false) | ||
213 | return false; | ||
214 | sd_read_response(&returncode, 1); | ||
215 | if (sd_send_command(cmd, arg1, arg2) == false) | ||
216 | return false; | ||
217 | return true; | 240 | return true; |
218 | } | 241 | } |
219 | 242 | ||
220 | void sd_wait_for_state(tSDCardInfo* card, unsigned int state) | 243 | static void sd_wait_for_state(unsigned int state, unsigned int id) |
221 | { | 244 | { |
222 | unsigned int response = 0; | 245 | unsigned int response = 0; |
223 | while(((response >> 9) & 0xf) != state) | 246 | |
247 | check_time[id] = USEC_TIMER; | ||
248 | |||
249 | while (1) | ||
224 | { | 250 | { |
225 | sd_send_command(SEND_STATUS, (card->rca) << 16, 1); | 251 | sd_command(SEND_STATUS, currcard->rca, &response, 1); |
252 | sd_check_timeout(0x80000, id); | ||
253 | |||
254 | if (((response >> 9) & 0xf) == state) | ||
255 | break; | ||
256 | |||
226 | priority_yield(); | 257 | priority_yield(); |
227 | sd_read_response(&response, 1); | ||
228 | /* TODO: Add a timeout and error handling */ | ||
229 | } | 258 | } |
259 | |||
230 | SD_STATE_REG = state; | 260 | SD_STATE_REG = state; |
231 | } | 261 | } |
232 | 262 | ||
233 | 263 | static inline void copy_read_sectors_fast(unsigned char **buf) | |
234 | STATICIRAM void copy_read_sectors(unsigned char* buf, int wordcount) | ||
235 | NOINLINE_ATTR ICODE_ATTR; | ||
236 | |||
237 | STATICIRAM void copy_read_sectors(unsigned char* buf, int wordcount) | ||
238 | { | 264 | { |
239 | unsigned int tmp = 0; | 265 | /* Copy one chunk of 16 words using best method for start alignment */ |
240 | 266 | switch ( (intptr_t)*buf & 3 ) | |
241 | if ( (unsigned long)buf & 1) | 267 | { |
242 | { /* not 16-bit aligned, copy byte by byte */ | 268 | case 0: |
243 | unsigned char* bufend = buf + wordcount*2; | 269 | asm volatile ( |
244 | do | 270 | "ldmia %[data], { r2-r9 } \r\n" |
245 | { | 271 | "orr r2, r2, r3, lsl #16 \r\n" |
246 | tmp = DATA_REG; | 272 | "orr r4, r4, r5, lsl #16 \r\n" |
247 | *buf++ = tmp & 0xff; | 273 | "orr r6, r6, r7, lsl #16 \r\n" |
248 | *buf++ = tmp >> 8; | 274 | "orr r8, r8, r9, lsl #16 \r\n" |
249 | } while (buf < bufend); /* tail loop is faster */ | 275 | "stmia %[buf]!, { r2, r4, r6, r8 } \r\n" |
250 | } | 276 | "ldmia %[data], { r2-r9 } \r\n" |
251 | else | 277 | "orr r2, r2, r3, lsl #16 \r\n" |
252 | { /* 16-bit aligned, can do faster copy */ | 278 | "orr r4, r4, r5, lsl #16 \r\n" |
253 | unsigned short* wbuf = (unsigned short*)buf; | 279 | "orr r6, r6, r7, lsl #16 \r\n" |
254 | unsigned short* wbufend = wbuf + wordcount; | 280 | "orr r8, r8, r9, lsl #16 \r\n" |
255 | do | 281 | "stmia %[buf]!, { r2, r4, r6, r8 } \r\n" |
256 | { | 282 | : [buf]"+&r"(*buf) |
257 | *wbuf = DATA_REG; | 283 | : [data]"r"(&DATA_REG) |
258 | } while (++wbuf < wbufend); /* tail loop is faster */ | 284 | : "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9" |
285 | ); | ||
286 | break; | ||
287 | case 1: | ||
288 | asm volatile ( | ||
289 | "ldmia %[data], { r2-r9 } \r\n" | ||
290 | "orr r3, r2, r3, lsl #16 \r\n" | ||
291 | "strb r3, [%[buf]], #1 \r\n" | ||
292 | "mov r3, r3, lsr #8 \r\n" | ||
293 | "strh r3, [%[buf]], #2 \r\n" | ||
294 | "mov r3, r3, lsr #16 \r\n" | ||
295 | "orr r3, r3, r4, lsl #8 \r\n" | ||
296 | "orr r3, r3, r5, lsl #24 \r\n" | ||
297 | "mov r5, r5, lsr #8 \r\n" | ||
298 | "orr r5, r5, r6, lsl #8 \r\n" | ||
299 | "orr r5, r5, r7, lsl #24 \r\n" | ||
300 | "mov r7, r7, lsr #8 \r\n" | ||
301 | "orr r7, r7, r8, lsl #8 \r\n" | ||
302 | "orr r7, r7, r9, lsl #24 \r\n" | ||
303 | "mov r2, r9, lsr #8 \r\n" | ||
304 | "stmia %[buf]!, { r3, r5, r7 } \r\n" | ||
305 | "ldmia %[data], { r3-r10 } \r\n" | ||
306 | "orr r2, r2, r3, lsl #8 \r\n" | ||
307 | "orr r2, r2, r4, lsl #24 \r\n" | ||
308 | "mov r4, r4, lsr #8 \r\n" | ||
309 | "orr r4, r4, r5, lsl #8 \r\n" | ||
310 | "orr r4, r4, r6, lsl #24 \r\n" | ||
311 | "mov r6, r6, lsr #8 \r\n" | ||
312 | "orr r6, r6, r7, lsl #8 \r\n" | ||
313 | "orr r6, r6, r8, lsl #24 \r\n" | ||
314 | "mov r8, r8, lsr #8 \r\n" | ||
315 | "orr r8, r8, r9, lsl #8 \r\n" | ||
316 | "orr r8, r8, r10, lsl #24 \r\n" | ||
317 | "mov r10, r10, lsr #8 \r\n" | ||
318 | "stmia %[buf]!, { r2, r4, r6, r8 } \r\n" | ||
319 | "strb r10, [%[buf]], #1 \r\n" | ||
320 | : [buf]"+&r"(*buf) | ||
321 | : [data]"r"(&DATA_REG) | ||
322 | : "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10" | ||
323 | ); | ||
324 | break; | ||
325 | case 2: | ||
326 | asm volatile ( | ||
327 | "ldmia %[data], { r2-r9 } \r\n" | ||
328 | "strh r2, [%[buf]], #2 \r\n" | ||
329 | "orr r3, r3, r4, lsl #16 \r\n" | ||
330 | "orr r5, r5, r6, lsl #16 \r\n" | ||
331 | "orr r7, r7, r8, lsl #16 \r\n" | ||
332 | "stmia %[buf]!, { r3, r5, r7 } \r\n" | ||
333 | "ldmia %[data], { r2-r8, r10 } \r\n" | ||
334 | "orr r2, r9, r2, lsl #16 \r\n" | ||
335 | "orr r3, r3, r4, lsl #16 \r\n" | ||
336 | "orr r5, r5, r6, lsl #16 \r\n" | ||
337 | "orr r7, r7, r8, lsl #16 \r\n" | ||
338 | "stmia %[buf]!, { r2, r3, r5, r7 } \r\n" | ||
339 | "strh r10, [%[buf]], #2 \r\n" | ||
340 | : [buf]"+&r"(*buf) | ||
341 | : [data]"r"(&DATA_REG) | ||
342 | : "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10" | ||
343 | ); | ||
344 | break; | ||
345 | case 3: | ||
346 | asm volatile ( | ||
347 | "ldmia %[data], { r2-r9 } \r\n" | ||
348 | "orr r3, r2, r3, lsl #16 \r\n" | ||
349 | "strb r3, [%[buf]], #1 \r\n" | ||
350 | "mov r3, r3, lsr #8 \r\n" | ||
351 | "orr r3, r3, r4, lsl #24 \r\n" | ||
352 | "mov r4, r4, lsr #8 \r\n" | ||
353 | "orr r5, r4, r5, lsl #8 \r\n" | ||
354 | "orr r5, r5, r6, lsl #24 \r\n" | ||
355 | "mov r6, r6, lsr #8 \r\n" | ||
356 | "orr r7, r6, r7, lsl #8 \r\n" | ||
357 | "orr r7, r7, r8, lsl #24 \r\n" | ||
358 | "mov r8, r8, lsr #8 \r\n" | ||
359 | "orr r2, r8, r9, lsl #8 \r\n" | ||
360 | "stmia %[buf]!, { r3, r5, r7 } \r\n" | ||
361 | "ldmia %[data], { r3-r10 } \r\n" | ||
362 | "orr r2, r2, r3, lsl #24 \r\n" | ||
363 | "mov r3, r3, lsr #8 \r\n" | ||
364 | "orr r4, r3, r4, lsl #8 \r\n" | ||
365 | "orr r4, r4, r5, lsl #24 \r\n" | ||
366 | "mov r5, r5, lsr #8 \r\n" | ||
367 | "orr r6, r5, r6, lsl #8 \r\n" | ||
368 | "orr r6, r6, r7, lsl #24 \r\n" | ||
369 | "mov r7, r7, lsr #8 \r\n" | ||
370 | "orr r8, r7, r8, lsl #8 \r\n" | ||
371 | "orr r8, r8, r9, lsl #24 \r\n" | ||
372 | "mov r9, r9, lsr #8 \r\n" | ||
373 | "orr r10, r9, r10, lsl #8 \r\n" | ||
374 | "stmia %[buf]!, { r2, r4, r6, r8 } \r\n" | ||
375 | "strh r10, [%[buf]], #2 \r\n" | ||
376 | "mov r10, r10, lsr #16 \r\n" | ||
377 | "strb r10, [%[buf]], #1 \r\n" | ||
378 | : [buf]"+&r"(*buf) | ||
379 | : [data]"r"(&DATA_REG) | ||
380 | : "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10" | ||
381 | ); | ||
382 | break; | ||
259 | } | 383 | } |
260 | } | 384 | } |
261 | 385 | ||
262 | STATICIRAM void copy_write_sectors(const unsigned char* buf, int wordcount) | 386 | static inline void copy_read_sectors_slow(unsigned char** buf) |
263 | NOINLINE_ATTR ICODE_ATTR; | 387 | { |
388 | int cnt = FIFO_SIZE; | ||
389 | int t; | ||
390 | |||
391 | /* Copy one chunk of 16 words */ | ||
392 | asm volatile ( | ||
393 | "1: \r\n" | ||
394 | "ldrh %[t], [%[data]] \r\n" | ||
395 | "strb %[t], [%[buf]], #1 \r\n" | ||
396 | "mov %[t], %[t], lsr #8 \r\n" | ||
397 | "strb %[t], [%[buf]], #1 \r\n" | ||
398 | "subs %[cnt], %[cnt], #1 \r\n" | ||
399 | "bgt 1b \r\n" | ||
400 | : [cnt]"+&r"(cnt), [buf]"+&r"(*buf), | ||
401 | [t]"=&r"(t) | ||
402 | : [data]"r"(&DATA_REG) | ||
403 | ); | ||
404 | } | ||
264 | 405 | ||
265 | STATICIRAM void copy_write_sectors(const unsigned char* buf, int wordcount) | 406 | /* Writes have to be kept slow for now */ |
407 | static inline void copy_write_sectors(const unsigned char* buf) | ||
266 | { | 408 | { |
267 | unsigned short tmp = 0; | 409 | unsigned short tmp = 0; |
268 | const unsigned char* bufend = buf + wordcount*2; | 410 | const unsigned char* bufend = buf + FIFO_SIZE*2; |
411 | |||
269 | do | 412 | do |
270 | { | 413 | { |
271 | tmp = (unsigned short) *buf++; | 414 | tmp = (unsigned short) *buf++; |
272 | tmp |= (unsigned short) *buf++ << 8; | 415 | tmp |= (unsigned short) *buf++ << 8; |
273 | DATA_REG = tmp; | 416 | DATA_REG = tmp; |
274 | } while (buf < bufend); /* tail loop is faster */ | 417 | } while (buf < bufend); /* tail loop is faster */ |
275 | } | 418 | } |
276 | 419 | ||
277 | 420 | static void sd_select_bank(unsigned char bank) | |
278 | void sd_select_bank(unsigned char bank) | ||
279 | { | 421 | { |
280 | unsigned int response; | 422 | unsigned int response; |
281 | unsigned char card_data[512]; | 423 | unsigned char card_data[512]; |
282 | unsigned char* write_buf; | 424 | unsigned char* write_buf; |
283 | int i; | 425 | int i; |
284 | tSDCardInfo *card = &card_info[0]; /* Bank selection will only be done on | ||
285 | the onboard flash */ | ||
286 | if (current_bank != bank) | ||
287 | { | ||
288 | memset(card_data, 0, 512); | ||
289 | sd_wait_for_state(card, TRAN); | ||
290 | BLOCK_SIZE_REG = 512; | ||
291 | BLOCK_COUNT_REG = 1; | ||
292 | sd_send_command(35, 0, 0x1c0d); /* CMD35 is vendor specific */ | ||
293 | sd_read_response(&response, 1); | ||
294 | SD_STATE_REG = PRG; | ||
295 | 426 | ||
296 | card_data[0] = bank; | 427 | memset(card_data, 0, 512); |
428 | sd_wait_for_state(TRAN, EC_TRAN_SEL_BANK); | ||
429 | BLOCK_SIZE_REG = 512; | ||
430 | BLOCK_COUNT_REG = 1; | ||
431 | sd_command(35, 0, &response, 0x1c0d); /* CMD35 is vendor specific */ | ||
432 | SD_STATE_REG = PRG; | ||
297 | 433 | ||
298 | /* Write the card data */ | 434 | card_data[0] = bank; |
299 | write_buf = card_data; | ||
300 | for (i = 0; i < BLOCK_SIZE / 2; i += FIFO_SIZE) | ||
301 | { | ||
302 | /* Wait for the FIFO to be empty */ | ||
303 | while((STATUS_REG & FIFO_EMPTY) == 0) {} /* Erm... is this right? */ | ||
304 | 435 | ||
305 | copy_write_sectors(write_buf, FIFO_SIZE); | 436 | /* Write the card data */ |
437 | write_buf = card_data; | ||
438 | for (i = 0; i < BLOCK_SIZE / 2; i += FIFO_SIZE) | ||
439 | { | ||
440 | /* Wait for the FIFO to empty */ | ||
441 | sd_poll_status(FIFO_EMPTY, 10000, EC_FIFO_SEL_BANK_EMPTY | DO_PANIC); | ||
306 | 442 | ||
307 | write_buf += FIFO_SIZE*2; /* Advance one chunk of 16 words */ | 443 | copy_write_sectors(write_buf); /* Copy one chunk of 16 words */ |
308 | } | ||
309 | 444 | ||
310 | while((STATUS_REG & DATA_DONE) == 0) {} | 445 | write_buf += FIFO_SIZE*2; /* Advance one chunk of 16 words */ |
311 | current_bank = bank; | ||
312 | } | 446 | } |
447 | |||
448 | sd_poll_status(DATA_DONE, 10000, EC_FIFO_SEL_BANK_DONE | DO_PANIC); | ||
449 | |||
450 | currcard->current_bank = bank; | ||
313 | } | 451 | } |
314 | 452 | ||
315 | void sd_init_device(void) | 453 | /* lock must already be aquired */ |
454 | static void sd_init_device(int card_no) | ||
316 | { | 455 | { |
317 | /* SD Protocol registers */ | 456 | /* SD Protocol registers */ |
318 | unsigned int dummy; | 457 | unsigned int i, dummy; |
319 | int i; | 458 | unsigned int c_size = 0; |
320 | 459 | unsigned long c_mult = 0; | |
321 | static unsigned int read_bl_len = 0; | ||
322 | static unsigned int c_size = 0; | ||
323 | static unsigned int c_size_mult = 0; | ||
324 | static unsigned long mult = 0; | ||
325 | |||
326 | unsigned char carddata[512]; | 460 | unsigned char carddata[512]; |
327 | unsigned char *dataptr; | 461 | unsigned char *dataptr; |
328 | tSDCardInfo *card = &card_info[0]; /* Init onboard flash only */ | ||
329 | |||
330 | /* Initialise card data as blank */ | ||
331 | card->initialized = false; | ||
332 | card->ocr = 0; | ||
333 | card->csd[0] = 0; | ||
334 | card->csd[1] = 0; | ||
335 | card->csd[2] = 0; | ||
336 | card->cid[0] = 0; | ||
337 | card->cid[1] = 0; | ||
338 | card->cid[2] = 0; | ||
339 | card->rca = 0; | ||
340 | |||
341 | card->capacity = 0; | ||
342 | card->numblocks = 0; | ||
343 | card->block_size = 0; | ||
344 | card->block_exp = 0; | ||
345 | 462 | ||
346 | /* Enable and initialise controller */ | 463 | /* Enable and initialise controller */ |
347 | GPIOG_ENABLE |= (0x3 << 5); | ||
348 | GPIOG_OUTPUT_EN |= (0x3 << 5); | ||
349 | GPIOG_OUTPUT_VAL |= (0x3 << 5); | ||
350 | outl(inl(0x70000088) & ~(0x4), 0x70000088); | ||
351 | outl(inl(0x7000008c) & ~(0x4), 0x7000008c); | ||
352 | outl(inl(0x70000080) | 0x4, 0x70000080); | ||
353 | outl(inl(0x70000084) | 0x4, 0x70000084); | ||
354 | REG_1 = 6; | 464 | REG_1 = 6; |
355 | outl(inl(0x70000014) & ~(0x3ffff), 0x70000014); | ||
356 | outl((inl(0x70000014) & ~(0x3ffff)) | 0x255aa, 0x70000014); | ||
357 | outl(0x1010, 0x70000034); | ||
358 | |||
359 | GPIOA_ENABLE |= (1 << 7); | ||
360 | GPIOA_OUTPUT_EN &= ~(1 << 7); | ||
361 | GPIOD_ENABLE |= (0x1f); | ||
362 | GPIOD_OUTPUT_EN |= (0x1f); | ||
363 | GPIOD_OUTPUT_VAL |= (0x1f); | ||
364 | DEV_EN |= DEV_ATA; /* Enable controller */ | ||
365 | DEV_RS |= DEV_ATA; /* Reset controller */ | ||
366 | DEV_RS &=~DEV_ATA; /* Clear Reset */ | ||
367 | 465 | ||
368 | /* Init NAND */ | 466 | currcard = &card_info[card_no]; |
369 | REG_11 |= (1 << 15); | 467 | |
370 | REG_12 |= (1 << 15); | 468 | /* Initialise card data as blank */ |
469 | memset(currcard, 0, sizeof(*currcard)); | ||
470 | |||
471 | if (card_no == 0) | ||
472 | { | ||
473 | outl(inl(0x70000080) | 0x4, 0x70000080); | ||
474 | |||
475 | GPIOA_ENABLE &= ~0x7a; | ||
476 | GPIOA_OUTPUT_EN &= ~0x7a; | ||
477 | GPIOD_ENABLE |= 0x1f; | ||
478 | GPIOD_OUTPUT_VAL |= 0x1f; | ||
479 | GPIOD_OUTPUT_EN |= 0x1f; | ||
480 | |||
481 | outl((inl(0x70000014) & ~(0x3ffff)) | 0x255aa, 0x70000014); | ||
482 | } | ||
483 | else | ||
484 | { | ||
485 | outl(inl(0x70000080) & ~0x4, 0x70000080); | ||
486 | |||
487 | GPIOD_ENABLE &= ~0x1f; | ||
488 | GPIOD_OUTPUT_EN &= ~0x1f; | ||
489 | GPIOA_ENABLE |= 0x7a; | ||
490 | GPIOA_OUTPUT_VAL |= 0x7a; | ||
491 | GPIOA_OUTPUT_EN |= 0x7a; | ||
492 | |||
493 | outl(inl(0x70000014) & ~(0x3ffff), 0x70000014); | ||
494 | } | ||
495 | |||
496 | /* Init NAND */ | ||
497 | REG_11 |= (1 << 15); | ||
498 | REG_12 |= (1 << 15); | ||
371 | REG_12 &= ~(3 << 12); | 499 | REG_12 &= ~(3 << 12); |
372 | REG_12 |= (1 << 13); | 500 | REG_12 |= (1 << 13); |
373 | REG_11 &= ~(3 << 12); | 501 | REG_11 &= ~(3 << 12); |
374 | REG_11 |= (1 << 13); | 502 | REG_11 |= (1 << 13); |
503 | |||
504 | DEV_EN |= DEV_ATA; /* Enable controller */ | ||
505 | DEV_RS |= DEV_ATA; /* Reset controller */ | ||
506 | DEV_RS &=~DEV_ATA; /* Clear Reset */ | ||
375 | 507 | ||
376 | SD_STATE_REG = TRAN; | 508 | SD_STATE_REG = TRAN; |
377 | REG_5 = 0xf; | ||
378 | 509 | ||
379 | sd_send_command(GO_IDLE_STATE, 0, 256); | 510 | REG_5 = 0xf; |
380 | while ((card->ocr & (1 << 31)) == 0) /* Loop until the card is powered up */ | 511 | sd_command(GO_IDLE_STATE, 0, &dummy, 256); |
512 | check_time[EC_POWER_UP] = USEC_TIMER; | ||
513 | while ((currcard->ocr & (1 << 31)) == 0) /* until card is powered up */ | ||
381 | { | 514 | { |
382 | sd_send_acommand(SD_APP_OP_COND, 0x100000, 3); | 515 | sd_command(APP_CMD, currcard->rca, &dummy, 1); |
383 | sd_read_response(&(card->ocr), 3); | 516 | sd_command(SD_APP_OP_COND, 0x100000, &currcard->ocr, 3); |
384 | 517 | sd_check_timeout(5000000, EC_POWER_UP); | |
385 | if (card->ocr == 0) | ||
386 | { | ||
387 | /* TODO: Handle failure */ | ||
388 | while (1) {}; | ||
389 | } | ||
390 | } | 518 | } |
391 | 519 | ||
392 | sd_send_command(ALL_SEND_CID, 0, 2); | 520 | sd_command(ALL_SEND_CID, 0, currcard->cid, 2); |
393 | sd_read_response(card->cid, 2); | 521 | sd_command(SEND_RELATIVE_ADDR, 0, &currcard->rca, 1); |
394 | sd_send_command(SEND_RELATIVE_ADDR, 0, 1); | 522 | sd_command(SEND_CSD, currcard->rca, currcard->csd, 2); |
395 | sd_read_response(&card->rca, 1); | ||
396 | card->rca >>= 16; /* The Relative Card Address is the top 16 bits of the | ||
397 | 32 bits returned. Whenever it is used, it gets | ||
398 | shifted left by 16 bits, so this step could possibly | ||
399 | be skipped. */ | ||
400 | 523 | ||
401 | sd_send_command(SEND_CSD, card->rca << 16, 2); | ||
402 | sd_read_response(card->csd, 2); | ||
403 | |||
404 | /* Parse disk geometry */ | ||
405 | /* These calculations come from the Sandisk SD card product manual */ | 524 | /* These calculations come from the Sandisk SD card product manual */ |
406 | read_bl_len = ((card->csd[2] >> 16) & 0xf); | 525 | c_size = ((currcard->csd[2] & 0x3ff) << 2) + (currcard->csd[1] >> 30) + 1; |
407 | c_size = ((card->csd[2] & (0x3ff)) << 2) + | 526 | c_mult = 4 << ((currcard->csd[1] >> 15) & 7); |
408 | ((card->csd[1] & (0xc0000000)) >> 30); | 527 | currcard->max_read_bl_len = 1 << ((currcard->csd[2] >> 16) & 15); |
409 | c_size_mult = ((card->csd[1] >> 15) & 0x7); | 528 | currcard->block_size = BLOCK_SIZE; /* Always use 512 byte blocks */ |
410 | mult = (1<<(c_size_mult + 2)); | 529 | currcard->numblocks = c_size * c_mult * (currcard->max_read_bl_len / 512); |
411 | card->max_read_bl_len = (1<<read_bl_len); | 530 | currcard->capacity = currcard->numblocks * currcard->block_size; |
412 | card->block_size = BLOCK_SIZE; /* Always use 512 byte blocks */ | ||
413 | card->numblocks = (c_size + 1) * mult * (card->max_read_bl_len / 512); | ||
414 | card->capacity = card->numblocks * card->block_size; | ||
415 | 531 | ||
416 | REG_1 = 0; | 532 | REG_1 = 0; |
417 | sd_send_command(SELECT_CARD, card->rca << 16, 129); | 533 | |
418 | sd_read_response(&dummy, 1); /* I don't think we use the result from this */ | 534 | sd_command(SELECT_CARD, currcard->rca , &dummy, 129); |
419 | sd_send_acommand(SET_BUS_WIDTH, (card->rca << 16) | 2, 1); | 535 | sd_command(APP_CMD, currcard->rca , &dummy, 1); |
420 | sd_read_response(&dummy, 1); /* 4 bit wide bus */ | 536 | sd_command(SET_BUS_WIDTH, currcard->rca | 2 , &dummy, 1); /* 4 bit */ |
421 | sd_send_command(SET_BLOCKLEN, card->block_size, 1); | 537 | sd_command(SET_BLOCKLEN, currcard->block_size, &dummy, 1); |
422 | sd_read_response(&dummy, 1); | 538 | BLOCK_SIZE_REG = currcard->block_size; |
423 | BLOCK_SIZE_REG = card->block_size; | ||
424 | 539 | ||
425 | /* If this card is > 4Gb, then we need to enable bank switching */ | 540 | /* If this card is > 4Gb, then we need to enable bank switching */ |
426 | if(card->numblocks >= BLOCKS_PER_BANK) | 541 | if(currcard->numblocks >= BLOCKS_PER_BANK) |
427 | { | 542 | { |
428 | SD_STATE_REG = TRAN; | 543 | SD_STATE_REG = TRAN; |
429 | BLOCK_COUNT_REG = 1; | 544 | BLOCK_COUNT_REG = 1; |
430 | sd_send_command(SWITCH_FUNC, 0x80ffffef, 0x1c05); | 545 | sd_command(SWITCH_FUNC, 0x80ffffef, &dummy, 0x1c05); |
431 | sd_read_response(&dummy, 1); | ||
432 | /* Read 512 bytes from the card. | 546 | /* Read 512 bytes from the card. |
433 | The first 512 bits contain the status information | 547 | The first 512 bits contain the status information |
434 | TODO: Do something useful with this! */ | 548 | TODO: Do something useful with this! */ |
@@ -436,206 +550,216 @@ void sd_init_device(void) | |||
436 | for (i = 0; i < BLOCK_SIZE / 2; i += FIFO_SIZE) | 550 | for (i = 0; i < BLOCK_SIZE / 2; i += FIFO_SIZE) |
437 | { | 551 | { |
438 | /* Wait for the FIFO to be full */ | 552 | /* Wait for the FIFO to be full */ |
439 | while((STATUS_REG & FIFO_FULL) == 0) {} | 553 | sd_poll_status(FIFO_FULL, 100000, |
440 | 554 | EC_FIFO_ENA_BANK_EMPTY | DO_PANIC); | |
441 | copy_read_sectors(dataptr, FIFO_SIZE); | 555 | copy_read_sectors_slow(&dataptr); |
442 | |||
443 | dataptr += (FIFO_SIZE*2); /* Advance one chunk of 16 words */ | ||
444 | } | 556 | } |
445 | } | 557 | } |
446 | spinlock_init(&sd_mtx); | 558 | |
559 | currcard->initialized = true; | ||
447 | } | 560 | } |
448 | 561 | ||
449 | /* API Functions */ | 562 | /* API Functions */ |
450 | 563 | ||
451 | void ata_led(bool onoff) | 564 | void ata_led(bool onoff) |
452 | { | 565 | { |
453 | (void)onoff; | 566 | led(onoff); |
454 | } | 567 | } |
455 | 568 | ||
456 | int ata_read_sectors(IF_MV2(int drive,) | 569 | int ata_read_sectors(IF_MV2(int drive,) unsigned long start, int incount, |
457 | unsigned long start, | ||
458 | int incount, | ||
459 | void* inbuf) | 570 | void* inbuf) |
460 | { | 571 | { |
461 | int ret = 0; | 572 | int ret = 0; |
462 | long timeout; | 573 | unsigned char *buf, *buf_end; |
463 | int count; | ||
464 | void* buf; | ||
465 | long spinup_start; | ||
466 | unsigned int dummy; | 574 | unsigned int dummy; |
467 | unsigned int response; | 575 | int bank; |
468 | unsigned int i; | 576 | |
469 | tSDCardInfo *card = &card_info[current_card]; | ||
470 | |||
471 | /* TODO: Add DMA support. */ | 577 | /* TODO: Add DMA support. */ |
472 | 578 | ||
473 | #ifdef HAVE_MULTIVOLUME | ||
474 | (void)drive; /* unused for now */ | ||
475 | #endif | ||
476 | spinlock_lock(&sd_mtx); | 579 | spinlock_lock(&sd_mtx); |
477 | 580 | ||
478 | last_disk_activity = current_tick; | ||
479 | spinup_start = current_tick; | ||
480 | |||
481 | ata_enable(true); | ||
482 | ata_led(true); | 581 | ata_led(true); |
483 | 582 | ||
484 | timeout = current_tick + READ_TIMEOUT; | 583 | if (drive != 0 && (GPIOA_INPUT_VAL & 0x80) != 0) |
485 | |||
486 | /* TODO: Select device */ | ||
487 | if(current_card == 0) | ||
488 | { | 584 | { |
489 | if(start >= BLOCKS_PER_BANK) | 585 | /* no external sd-card inserted */ |
490 | { | 586 | ret = -9; |
491 | sd_select_bank(1); | 587 | goto ata_read_error; |
492 | start -= BLOCKS_PER_BANK; | ||
493 | } else { | ||
494 | sd_select_bank(0); | ||
495 | } | ||
496 | } | 588 | } |
497 | 589 | ||
498 | buf = inbuf; | 590 | if (&card_info[drive] != currcard || !card_info[drive].initialized) |
499 | count = incount; | 591 | sd_init_device(drive); |
500 | while (TIME_BEFORE(current_tick, timeout)) { | ||
501 | ret = 0; | ||
502 | last_disk_activity = current_tick; | ||
503 | 592 | ||
504 | SD_STATE_REG = TRAN; | 593 | last_disk_activity = current_tick; |
505 | BLOCK_COUNT_REG = count; | ||
506 | sd_send_command(READ_MULTIPLE_BLOCK, start * BLOCK_SIZE, 0x1c25); | ||
507 | sd_read_response(&dummy, 1); | ||
508 | /* TODO: Don't assume BLOCK_SIZE == SECTOR_SIZE */ | ||
509 | 594 | ||
510 | for (i = 0; i < count * card->block_size / 2; i += FIFO_SIZE) | 595 | bank = start / BLOCKS_PER_BANK; |
511 | { | ||
512 | /* Wait for the FIFO to be full */ | ||
513 | while((STATUS_REG & FIFO_FULL) == 0) {} | ||
514 | 596 | ||
515 | copy_read_sectors(buf, FIFO_SIZE); | 597 | if (currcard->current_bank != bank) |
598 | sd_select_bank(bank); | ||
516 | 599 | ||
517 | buf += FIFO_SIZE*2; /* Advance one chunk of 16 words */ | 600 | start -= bank * BLOCKS_PER_BANK; |
518 | 601 | ||
519 | /* TODO: Switch bank if necessary */ | 602 | sd_wait_for_state(TRAN, EC_TRAN_READ_ENTRY); |
603 | BLOCK_COUNT_REG = incount; | ||
604 | sd_command(READ_MULTIPLE_BLOCK, start * BLOCK_SIZE, &dummy, 0x1c25); | ||
605 | /* TODO: Don't assume BLOCK_SIZE == SECTOR_SIZE */ | ||
520 | 606 | ||
521 | last_disk_activity = current_tick; | 607 | buf_end = (unsigned char *)inbuf + incount * currcard->block_size; |
522 | } | 608 | for (buf = inbuf; buf < buf_end;) |
523 | udelay(75); | 609 | { |
524 | sd_send_command(STOP_TRANSMISSION, 0, 1); | 610 | /* Wait for the FIFO to be full */ |
525 | sd_read_response(&dummy, 1); | 611 | sd_poll_status(FIFO_FULL, 0x80000, EC_FIFO_READ_FULL | DO_PANIC); |
612 | copy_read_sectors_fast(&buf); /* Copy one chunk of 16 words */ | ||
526 | 613 | ||
527 | response = 0; | 614 | /* TODO: Switch bank if necessary */ |
528 | sd_wait_for_state(card, TRAN); | ||
529 | break; | ||
530 | } | 615 | } |
616 | |||
617 | last_disk_activity = current_tick; | ||
618 | #if 0 | ||
619 | udelay(75); | ||
620 | #endif | ||
621 | sd_command(STOP_TRANSMISSION, 0, &dummy, 1); | ||
622 | sd_wait_for_state(TRAN, EC_TRAN_READ_EXIT); | ||
623 | |||
624 | ata_read_error: | ||
531 | ata_led(false); | 625 | ata_led(false); |
532 | ata_enable(false); | ||
533 | 626 | ||
534 | spinlock_unlock(&sd_mtx); | 627 | spinlock_unlock(&sd_mtx); |
535 | 628 | ||
536 | return ret; | 629 | return ret; |
537 | } | 630 | } |
538 | 631 | ||
539 | 632 | int ata_write_sectors(IF_MV2(int drive,) unsigned long start, int count, | |
540 | int ata_write_sectors(IF_MV2(int drive,) | 633 | const void* outbuf) |
541 | unsigned long start, | ||
542 | int count, | ||
543 | const void* buf) | ||
544 | { | 634 | { |
545 | /* Write support is not finished yet */ | 635 | /* Write support is not finished yet */ |
546 | /* TODO: The standard suggests using ACMD23 prior to writing multiple blocks | 636 | /* TODO: The standard suggests using ACMD23 prior to writing multiple blocks |
547 | to improve performance */ | 637 | to improve performance */ |
548 | unsigned int response; | 638 | unsigned int response; |
549 | void const* write_buf; | 639 | void const* buf, *buf_end; |
550 | int ret = 0; | 640 | int ret = 0; |
551 | unsigned int i; | 641 | int bank; |
552 | long timeout; | ||
553 | tSDCardInfo *card = &card_info[current_card]; | ||
554 | 642 | ||
555 | spinlock_lock(&sd_mtx); | 643 | spinlock_lock(&sd_mtx); |
556 | ata_enable(true); | 644 | |
557 | ata_led(true); | 645 | ata_led(true); |
558 | if(current_card == 0) | 646 | |
647 | if (drive != 0 && (GPIOA_INPUT_VAL & 0x80) != 0) | ||
559 | { | 648 | { |
560 | if(start < BLOCKS_PER_BANK) | 649 | /* no external sd-card inserted */ |
561 | { | 650 | ret = -9; |
562 | sd_select_bank(0); | 651 | goto error; |
563 | } else { | ||
564 | sd_select_bank(1); | ||
565 | start -= BLOCKS_PER_BANK; | ||
566 | } | ||
567 | } | 652 | } |
568 | 653 | ||
569 | retry: | 654 | if (&card_info[drive] != currcard || !card_info[drive].initialized) |
570 | sd_wait_for_state(card, TRAN); | 655 | sd_init_device(drive); |
656 | |||
657 | bank = start / BLOCKS_PER_BANK; | ||
658 | |||
659 | if (currcard->current_bank != bank) | ||
660 | sd_select_bank(bank); | ||
661 | |||
662 | start -= bank * BLOCKS_PER_BANK; | ||
663 | |||
664 | check_time[EC_WRITE_TIMEOUT] = USEC_TIMER; | ||
665 | sd_wait_for_state(TRAN, EC_TRAN_WRITE_ENTRY); | ||
571 | BLOCK_COUNT_REG = count; | 666 | BLOCK_COUNT_REG = count; |
572 | sd_send_command(WRITE_MULTIPLE_BLOCK, start * SECTOR_SIZE, 0x1c2d); | 667 | sd_command(WRITE_MULTIPLE_BLOCK, start * SECTOR_SIZE, &response, 0x1c2d); |
573 | sd_read_response(&response, 1); | 668 | |
574 | write_buf = buf; | 669 | buf_end = outbuf + count * currcard->block_size; |
575 | for (i = 0; i < count * card->block_size / 2; i += FIFO_SIZE) | 670 | for (buf = outbuf; buf < buf_end; buf += 2 * FIFO_SIZE) |
576 | { | 671 | { |
577 | if(i >= (count * card->block_size / 2)-FIFO_SIZE) | 672 | if (buf >= buf_end - 2 * FIFO_SIZE) |
578 | { | 673 | { |
579 | /* Set SD_STATE_REG to PRG for the last buffer fill */ | 674 | /* Set SD_STATE_REG to PRG for the last buffer fill */ |
580 | SD_STATE_REG = PRG; | 675 | SD_STATE_REG = PRG; |
581 | } | 676 | } |
582 | 677 | ||
583 | /* Wait for the FIFO to be empty */ | 678 | udelay(2); /* needed here (loop is too fast :-) */ |
584 | while((STATUS_REG & FIFO_EMPTY) == 0) {} | ||
585 | /* Perhaps we could use bit 8 of card status (READY_FOR_DATA)? */ | ||
586 | 679 | ||
587 | copy_write_sectors(write_buf, FIFO_SIZE); | 680 | /* Wait for the FIFO to empty */ |
681 | sd_poll_status(FIFO_EMPTY, 0x80000, EC_FIFO_WR_EMPTY | DO_PANIC); | ||
588 | 682 | ||
589 | write_buf += FIFO_SIZE*2; /* Advance one chunk of 16 words */ | 683 | copy_write_sectors(buf); /* Copy one chunk of 16 words */ |
590 | /* TODO: Switch bank if necessary */ | ||
591 | 684 | ||
592 | last_disk_activity = current_tick; | 685 | /* TODO: Switch bank if necessary */ |
593 | } | 686 | } |
594 | 687 | ||
595 | timeout = current_tick + WRITE_TIMEOUT; | 688 | last_disk_activity = current_tick; |
596 | 689 | ||
597 | while((STATUS_REG & DATA_DONE) == 0) { | 690 | sd_poll_status(DATA_DONE, 0x80000, EC_FIFO_WR_DONE | DO_PANIC); |
598 | if(current_tick >= timeout) | 691 | sd_check_timeout(0x80000, EC_WRITE_TIMEOUT); |
599 | { | 692 | |
600 | sd_send_command(STOP_TRANSMISSION, 0, 1); | 693 | sd_command(STOP_TRANSMISSION, 0, &response, 1); |
601 | sd_read_response(&response, 1); | 694 | sd_wait_for_state(TRAN, EC_TRAN_WRITE_EXIT); |
602 | goto retry; | ||
603 | } | ||
604 | } | ||
605 | sd_send_command(STOP_TRANSMISSION, 0, 1); | ||
606 | sd_read_response(&response, 1); | ||
607 | 695 | ||
608 | sd_wait_for_state(card, TRAN); | 696 | error: |
609 | ata_led(false); | 697 | ata_led(false); |
610 | ata_enable(false); | ||
611 | spinlock_unlock(&sd_mtx); | 698 | spinlock_unlock(&sd_mtx); |
612 | 699 | ||
613 | return ret; | 700 | return ret; |
614 | } | 701 | } |
615 | 702 | ||
703 | static void sd_thread(void) __attribute__((noreturn)); | ||
616 | static void sd_thread(void) | 704 | static void sd_thread(void) |
617 | { | 705 | { |
618 | struct event ev; | 706 | struct event ev; |
619 | bool idle_notified = false; | 707 | bool idle_notified = false; |
620 | 708 | ||
621 | while (1) { | 709 | while (1) |
710 | { | ||
622 | queue_wait_w_tmo(&sd_queue, &ev, HZ); | 711 | queue_wait_w_tmo(&sd_queue, &ev, HZ); |
712 | |||
623 | switch ( ev.id ) | 713 | switch ( ev.id ) |
624 | { | 714 | { |
625 | default: | 715 | case SD_HOTSWAP: |
626 | if (TIME_BEFORE(current_tick, last_disk_activity+(3*HZ))) | 716 | { |
627 | { | 717 | int status = 0; |
628 | idle_notified = false; | 718 | enum { SD_UNMOUNTED = 0x1, SD_MOUNTED = 0x2 }; |
629 | } | 719 | |
630 | else | 720 | /* Delay on insert and remove to prevent reading state if it is |
631 | { | 721 | just bouncing back and forth while card is sliding - delay on |
632 | if (!idle_notified) | 722 | insert is also required for the card to stabilize and accept |
633 | { | 723 | commands */ |
634 | call_ata_idle_notifys(false); | 724 | sleep(HZ/10); |
635 | idle_notified = true; | 725 | |
636 | } | 726 | /* Lock to keep us from messing with this variable while an init |
637 | } | 727 | may be in progress */ |
638 | break; | 728 | spinlock_lock(&sd_mtx); |
729 | card_info[1].initialized = false; | ||
730 | spinlock_unlock(&sd_mtx); | ||
731 | |||
732 | /* Either unmount because the card was pulled or unmount and | ||
733 | remount if already mounted since multiple messages may be | ||
734 | generated for the same event - like someone inserting a new | ||
735 | card before anything detects the old one pulled :) */ | ||
736 | if (disk_unmount(1) != 0) /* release "by force" */ | ||
737 | status |= SD_UNMOUNTED; | ||
738 | |||
739 | if (card_detect_target() && disk_mount(1) != 0) /* mount SD-CARD */ | ||
740 | status |= SD_MOUNTED; | ||
741 | |||
742 | if (status & SD_UNMOUNTED) | ||
743 | queue_broadcast(SYS_HOTSWAP_EXTRACTED, 0); | ||
744 | |||
745 | if (status & SD_MOUNTED) | ||
746 | queue_broadcast(SYS_HOTSWAP_INSERTED, 0); | ||
747 | |||
748 | if (status) | ||
749 | queue_broadcast(SYS_FS_CHANGED, 0); | ||
750 | break; | ||
751 | } /* SD_HOTSWAP */ | ||
752 | case SYS_TIMEOUT: | ||
753 | if (TIME_BEFORE(current_tick, last_disk_activity+(3*HZ))) | ||
754 | { | ||
755 | idle_notified = false; | ||
756 | } | ||
757 | else if (!idle_notified) | ||
758 | { | ||
759 | call_ata_idle_notifys(false); | ||
760 | idle_notified = true; | ||
761 | } | ||
762 | break; | ||
639 | } | 763 | } |
640 | } | 764 | } |
641 | } | 765 | } |
@@ -648,7 +772,7 @@ void ata_spindown(int seconds) | |||
648 | 772 | ||
649 | bool ata_disk_is_active(void) | 773 | bool ata_disk_is_active(void) |
650 | { | 774 | { |
651 | return 0; | 775 | return 0; |
652 | } | 776 | } |
653 | 777 | ||
654 | void ata_sleep(void) | 778 | void ata_sleep(void) |
@@ -662,12 +786,12 @@ void ata_spin(void) | |||
662 | /* Hardware reset protocol as specified in chapter 9.1, ATA spec draft v5 */ | 786 | /* Hardware reset protocol as specified in chapter 9.1, ATA spec draft v5 */ |
663 | int ata_hard_reset(void) | 787 | int ata_hard_reset(void) |
664 | { | 788 | { |
665 | return 0; | 789 | return 0; |
666 | } | 790 | } |
667 | 791 | ||
668 | int ata_soft_reset(void) | 792 | int ata_soft_reset(void) |
669 | { | 793 | { |
670 | return 0; | 794 | return 0; |
671 | } | 795 | } |
672 | 796 | ||
673 | void ata_enable(bool on) | 797 | void ata_enable(bool on) |
@@ -682,22 +806,113 @@ void ata_enable(bool on) | |||
682 | } | 806 | } |
683 | } | 807 | } |
684 | 808 | ||
685 | unsigned short* ata_get_identify(void) | ||
686 | { | ||
687 | return identify_info; | ||
688 | } | ||
689 | |||
690 | int ata_init(void) | 809 | int ata_init(void) |
691 | { | 810 | { |
692 | sd_init_device(); | 811 | ata_led(false); |
693 | if ( !initialized ) | 812 | |
813 | /* NOTE: This init isn't dual core safe */ | ||
814 | if (!initialized) | ||
694 | { | 815 | { |
695 | queue_init(&sd_queue, true); | ||
696 | create_thread(sd_thread, sd_stack, | ||
697 | sizeof(sd_stack), sd_thread_name IF_PRIO(, PRIORITY_SYSTEM) | ||
698 | IF_COP(, CPU, false)); | ||
699 | initialized = true; | 816 | initialized = true; |
817 | |||
818 | spinlock_init(&sd_mtx); | ||
819 | |||
820 | spinlock_lock(&sd_mtx); | ||
821 | |||
822 | /* init controller */ | ||
823 | outl(inl(0x70000088) & ~(0x4), 0x70000088); | ||
824 | outl(inl(0x7000008c) & ~(0x4), 0x7000008c); | ||
825 | outl(inl(0x70000084) | 0x4, 0x70000084); | ||
826 | outl(0x1010, 0x70000034); | ||
827 | |||
828 | GPIOG_ENABLE |= (0x3 << 5); | ||
829 | GPIOG_OUTPUT_EN |= (0x3 << 5); | ||
830 | GPIOG_OUTPUT_VAL |= (0x3 << 5); | ||
831 | |||
832 | /* enable card detection port - mask interrupt first */ | ||
833 | GPIOA_INT_EN &= ~0x80; | ||
834 | |||
835 | GPIOA_OUTPUT_EN &= ~0x80; | ||
836 | GPIOA_ENABLE |= 0x80; | ||
837 | |||
838 | sd_init_device(0); | ||
839 | |||
840 | queue_init(&sd_queue, true); | ||
841 | create_thread(sd_thread, sd_stack, sizeof(sd_stack), | ||
842 | sd_thread_name IF_PRIO(, PRIORITY_SYSTEM) IF_COP(, CPU, false)); | ||
843 | |||
844 | /* enable interupt for the mSD card */ | ||
845 | sleep(HZ/10); | ||
846 | |||
847 | CPU_INT_EN = HI_MASK; | ||
848 | CPU_HI_INT_EN = GPIO0_MASK; | ||
849 | |||
850 | sd1_status = GPIOA_INPUT_VAL & 0x80; | ||
851 | GPIOA_INT_LEV = (GPIOA_INT_LEV & ~0x80) | (sd1_status ^ 0x80); | ||
852 | |||
853 | GPIOA_INT_CLR = 0x80; | ||
854 | GPIOA_INT_EN |= 0x80; | ||
855 | |||
856 | spinlock_unlock(&sd_mtx); | ||
700 | } | 857 | } |
701 | 858 | ||
702 | return 0; | 859 | return 0; |
703 | } | 860 | } |
861 | |||
862 | /* move the sd-card info to mmc struct */ | ||
863 | tCardInfo *card_get_info_target(int card_no) | ||
864 | { | ||
865 | int i, temp; | ||
866 | static tCardInfo card; | ||
867 | static const char mantissa[] = { /* *10 */ | ||
868 | 0, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80 }; | ||
869 | static const int exponent[] = { /* use varies */ | ||
870 | 1,10,100,1000,10000,100000,1000000,10000000,100000000,1000000000 }; | ||
871 | |||
872 | card.initialized = card_info[card_no].initialized; | ||
873 | card.ocr = card_info[card_no].ocr; | ||
874 | for(i=0; i<4; i++) card.csd[i] = card_info[card_no].csd[3-i]; | ||
875 | for(i=0; i<4; i++) card.cid[i] = card_info[card_no].cid[3-i]; | ||
876 | card.numblocks = card_info[card_no].numblocks; | ||
877 | card.blocksize = card_info[card_no].block_size; | ||
878 | card.size = card_info[card_no].capacity < 0xffffffff ? | ||
879 | card_info[card_no].capacity : 0xffffffff; | ||
880 | card.block_exp = card_info[card_no].block_exp; | ||
881 | temp = card_extract_bits(card.csd, 29, 3); | ||
882 | card.speed = mantissa[card_extract_bits(card.csd, 25, 4)] | ||
883 | * exponent[temp > 2 ? 7 : temp + 4]; | ||
884 | card.nsac = 100 * card_extract_bits(card.csd, 16, 8); | ||
885 | temp = card_extract_bits(card.csd, 13, 3); | ||
886 | card.tsac = mantissa[card_extract_bits(card.csd, 9, 4)] | ||
887 | * exponent[temp] / 10; | ||
888 | card.cid[0] = htobe32(card.cid[0]); /* ascii chars here */ | ||
889 | card.cid[1] = htobe32(card.cid[1]); /* ascii chars here */ | ||
890 | temp = *((char*)card.cid+13); /* adjust year<=>month, 1997 <=> 2000 */ | ||
891 | *((char*)card.cid+13) = (unsigned char)((temp >> 4) | (temp << 4)) + 3; | ||
892 | |||
893 | return &card; | ||
894 | } | ||
895 | |||
896 | bool card_detect_target(void) | ||
897 | { | ||
898 | /* 0x00:inserted, 0x80:not inserted */ | ||
899 | return (GPIOA_INPUT_VAL & 0x80) == 0; | ||
900 | } | ||
901 | |||
902 | /* called on insertion/removal interrupt */ | ||
903 | void microsd_int(void) | ||
904 | { | ||
905 | int status = GPIOA_INPUT_VAL & 0x80; | ||
906 | |||
907 | GPIOA_INT_LEV = (GPIOA_INT_LEV & ~0x80) | (status ^ 0x80); | ||
908 | GPIOA_INT_CLR = 0x80; | ||
909 | |||
910 | if (status == sd1_status) | ||
911 | return; | ||
912 | |||
913 | sd1_status = status; | ||
914 | |||
915 | /* Take final state only - insert/remove is bouncy */ | ||
916 | queue_remove_from_head(&sd_queue, SD_HOTSWAP); | ||
917 | queue_post(&sd_queue, SD_HOTSWAP, status); | ||
918 | } | ||
diff --git a/firmware/target/arm/sandisk/sansa-e200/ata-target.h b/firmware/target/arm/sandisk/sansa-e200/ata-target.h index dfdd3fe6ae..61884e0864 100644 --- a/firmware/target/arm/sandisk/sansa-e200/ata-target.h +++ b/firmware/target/arm/sandisk/sansa-e200/ata-target.h | |||
@@ -19,25 +19,4 @@ | |||
19 | #ifndef ATA_TARGET_H | 19 | #ifndef ATA_TARGET_H |
20 | #define ATA_TARGET_H | 20 | #define ATA_TARGET_H |
21 | 21 | ||
22 | #include "inttypes.h" | ||
23 | |||
24 | typedef struct | ||
25 | { | ||
26 | bool initialized; | ||
27 | |||
28 | unsigned int ocr; /* OCR register */ | ||
29 | unsigned int csd[4]; /* CSD register */ | ||
30 | unsigned int cid[4]; /* CID register */ | ||
31 | unsigned int rca; | ||
32 | |||
33 | uint64_t capacity; /* size in bytes */ | ||
34 | unsigned long numblocks; /* size in flash blocks */ | ||
35 | unsigned int block_size; /* block size in bytes */ | ||
36 | unsigned int max_read_bl_len;/* max read data block length */ | ||
37 | unsigned int block_exp; /* block size exponent */ | ||
38 | } tSDCardInfo; | ||
39 | |||
40 | tSDCardInfo *sd_card_info(int card_no); | ||
41 | bool sd_touched(void); | ||
42 | |||
43 | #endif | 22 | #endif |
diff --git a/firmware/target/arm/sandisk/sansa-e200/hotswap-target.h b/firmware/target/arm/sandisk/sansa-e200/hotswap-target.h new file mode 100644 index 0000000000..95cb26d2f7 --- /dev/null +++ b/firmware/target/arm/sandisk/sansa-e200/hotswap-target.h | |||
@@ -0,0 +1,45 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2007 by Antonius Hellmann | ||
11 | * | ||
12 | * All files in this archive are subject to the GNU General Public License. | ||
13 | * See the file COPYING in the source tree root for full license agreement. | ||
14 | * | ||
15 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
16 | * KIND, either express or implied. | ||
17 | * | ||
18 | ****************************************************************************/ | ||
19 | #ifndef HOTSWAP_TARGET_H | ||
20 | #define HOTSWAP_TARGET_H | ||
21 | |||
22 | #include "inttypes.h" | ||
23 | #include "hotswap.h" | ||
24 | |||
25 | typedef struct | ||
26 | { | ||
27 | bool initialized; | ||
28 | |||
29 | unsigned int ocr; /* OCR register */ | ||
30 | unsigned int csd[4]; /* CSD register */ | ||
31 | unsigned int cid[4]; /* CID register */ | ||
32 | unsigned int rca; | ||
33 | |||
34 | uint64_t capacity; /* size in bytes */ | ||
35 | unsigned long numblocks; /* size in flash blocks */ | ||
36 | unsigned int block_size; /* block size in bytes */ | ||
37 | unsigned int max_read_bl_len;/* max read data block length */ | ||
38 | unsigned int block_exp; /* block size exponent */ | ||
39 | unsigned char current_bank; /* The bank that we are working with */ | ||
40 | } tSDCardInfo; | ||
41 | |||
42 | tCardInfo *card_get_info_target(int card_no); | ||
43 | bool card_detect_target(void); | ||
44 | |||
45 | #endif | ||
diff --git a/firmware/target/arm/system-pp502x.c b/firmware/target/arm/system-pp502x.c index ef0c62dcf5..49ffdd300b 100644 --- a/firmware/target/arm/system-pp502x.c +++ b/firmware/target/arm/system-pp502x.c | |||
@@ -56,8 +56,11 @@ void irq(void) | |||
56 | /* TODO: this should really be in the target tree, but moving it there caused | 56 | /* TODO: this should really be in the target tree, but moving it there caused |
57 | crt0.S not to find it while linking */ | 57 | crt0.S not to find it while linking */ |
58 | /* TODO: Even if it isn't in the target tree, this should be the default case */ | 58 | /* TODO: Even if it isn't in the target tree, this should be the default case */ |
59 | #ifdef SANSA_E200 | ||
59 | extern void button_int(void); | 60 | extern void button_int(void); |
60 | extern void clickwheel_int(void); | 61 | extern void clickwheel_int(void); |
62 | extern void microsd_int(void); | ||
63 | #endif | ||
61 | 64 | ||
62 | void irq(void) | 65 | void irq(void) |
63 | { | 66 | { |
@@ -65,11 +68,15 @@ void irq(void) | |||
65 | if (CPU_INT_STAT & TIMER1_MASK) { | 68 | if (CPU_INT_STAT & TIMER1_MASK) { |
66 | TIMER1(); | 69 | TIMER1(); |
67 | } | 70 | } |
68 | else if (CPU_INT_STAT & TIMER2_MASK) | 71 | else if (CPU_INT_STAT & TIMER2_MASK) { |
69 | TIMER2(); | 72 | TIMER2(); |
73 | } | ||
70 | #ifdef SANSA_E200 | 74 | #ifdef SANSA_E200 |
71 | else if (CPU_HI_INT_STAT & GPIO1_MASK) | 75 | else if (CPU_HI_INT_STAT & GPIO0_MASK) { |
72 | { | 76 | if (GPIOA_INT_STAT & 0x80) |
77 | microsd_int(); | ||
78 | } | ||
79 | else if (CPU_HI_INT_STAT & GPIO1_MASK) { | ||
73 | if (GPIOF_INT_STAT & 0xff) | 80 | if (GPIOF_INT_STAT & 0xff) |
74 | button_int(); | 81 | button_int(); |
75 | if (GPIOH_INT_STAT & 0xc0) | 82 | if (GPIOH_INT_STAT & 0xc0) |
diff --git a/firmware/usb.c b/firmware/usb.c index 217aaf8b84..9e9cb77919 100644 --- a/firmware/usb.c +++ b/firmware/usb.c | |||
@@ -255,8 +255,8 @@ static void usb_thread(void) | |||
255 | break; | 255 | break; |
256 | 256 | ||
257 | #ifdef HAVE_MMC | 257 | #ifdef HAVE_MMC |
258 | case SYS_MMC_INSERTED: | 258 | case SYS_HOTSWAP_INSERTED: |
259 | case SYS_MMC_EXTRACTED: | 259 | case SYS_HOTSWAP_EXTRACTED: |
260 | if(usb_state == USB_INSERTED) | 260 | if(usb_state == USB_INSERTED) |
261 | { | 261 | { |
262 | usb_enable(false); | 262 | usb_enable(false); |