| Index: emcore/trunk/target/ipodclassic/storage_ata.c | 
| — | — | @@ -109,6 +109,16 @@ | 
| 110 | 110 | ata_error_srst = enable; | 
| 111 | 111 | } | 
| 112 | 112 |  | 
|  | 113 | +int ata_lock_exclusive(int timeout) | 
|  | 114 | +{ | 
|  | 115 | +    return mutex_lock(&ata_mutex, timeout); | 
|  | 116 | +} | 
|  | 117 | + | 
|  | 118 | +void ata_unlock_exclusive() | 
|  | 119 | +{ | 
|  | 120 | +    mutex_unlock(&ata_mutex); | 
|  | 121 | +} | 
|  | 122 | + | 
| 113 | 123 | static uint16_t ata_read_cbr(uint32_t volatile* reg) | 
| 114 | 124 | { | 
| 115 | 125 | while (!(ATA_PIO_READY & 2)) yield(); | 
| — | — | @@ -1323,7 +1333,10 @@ | 
| 1324 | 1334 |  | 
| 1325 | 1335 | int ata_init(void) | 
| 1326 | 1336 | { | 
| 1327 |  | -    mutex_init(&ata_mutex); | 
|  | 1337 | +    // Remove this, as it isn't strictly required and causes a race condition. | 
|  | 1338 | +    // The clickwheel dispatcher can run ata_lock_exclusive before ata_init is run. | 
|  | 1339 | +    // BSS is initialized to zeroes, which are interpreted as an unlocked mutex anyway. | 
|  | 1340 | +    //mutex_init(&ata_mutex); | 
| 1328 | 1341 | wakeup_init(&ata_wakeup); | 
| 1329 | 1342 | wakeup_init(&mmc_wakeup); | 
| 1330 | 1343 | wakeup_init(&mmc_comp_wakeup); | 
| Index: emcore/trunk/target/ipodclassic/storage_ata-target.h | 
| — | — | @@ -68,6 +68,8 @@ | 
| 69 | 69 |  | 
| 70 | 70 | extern void ata_set_retries(int retries); | 
| 71 | 71 | extern void ata_srst_after_error(bool enable); | 
|  | 72 | +extern int ata_lock_exclusive(int timeout); | 
|  | 73 | +extern void ata_unlock_exclusive(); | 
| 72 | 74 | extern int ata_soft_reset(); | 
| 73 | 75 | extern int ata_hard_reset(); | 
| 74 | 76 | extern int ata_read_taskfile(struct ata_raw_cmd_t* cmd); | 
| Index: emcore/trunk/target/ipodnano2g/clickwheel.c | 
| — | — | @@ -31,13 +31,15 @@ | 
| 32 | 32 |  | 
| 33 | 33 |  | 
| 34 | 34 | static struct wakeup clickwheel_wakeup IBSS_ATTR; | 
|  | 35 | +static struct wakeup clickwheel_init_wakeup INITDATA_ATTR; | 
| 35 | 36 | static volatile uint32_t clickwheel_packet IBSS_ATTR; | 
| 36 | 37 | static struct scheduler_thread clickwheel_thread_handle; | 
| 37 | 38 | static uint32_t clickwheel_stack[0x100] STACK_ATTR; | 
|  | 39 | +static bool wheel_initialized IBSS_ATTR; | 
| 38 | 40 | static bool oldtouched IBSS_ATTR; | 
| 39 | 41 | static int oldpos IBSS_ATTR; | 
| 40 | 42 | static int oldbuttons IBSS_ATTR; | 
| 41 |  | -static uint32_t lastpacket IBSS_ATTR;
 | 
|  | 43 | +static int lastpacket IBSS_ATTR; | 
| 42 | 44 | static int packets IBSS_ATTR; | 
| 43 | 45 | static int collect IBSS_ATTR; | 
| 44 | 46 | static int lastdiff IBSS_ATTR; | 
| — | — | @@ -124,14 +126,21 @@ | 
| 125 | 127 | { | 
| 126 | 128 | if (data & 0x1F0000) oldbuttons = (data >> 16) & 0x1F; | 
| 127 | 129 | DEBUGF("This is an init packet, button state: %02X", oldbuttons); | 
|  | 130 | +            if (!wheel_initialized) | 
|  | 131 | +            { | 
|  | 132 | +                wheel_initialized = true; | 
|  | 133 | +                wakeup_signal(&clickwheel_init_wakeup); | 
|  | 134 | +            } | 
| 128 | 135 | } | 
| 129 | 136 | } | 
| 130 | 137 | } | 
| 131 | 138 |  | 
| 132 | 139 |  | 
| 133 |  | -void clickwheel_init()
 | 
|  | 140 | +int clickwheel_init() | 
| 134 | 141 | { | 
| 135 | 142 | wakeup_init(&clickwheel_wakeup); | 
|  | 143 | +    wakeup_init(&clickwheel_init_wakeup); | 
|  | 144 | +    wheel_initialized = false; | 
| 136 | 145 | oldtouched = false; | 
| 137 | 146 | oldbuttons = 0; | 
| 138 | 147 | lastpacket = 0; | 
| — | — | @@ -154,6 +163,9 @@ | 
| 155 | 164 | thread_create(&clickwheel_thread_handle, "Clickwheel dispatcher", clickwheel_thread, | 
| 156 | 165 | clickwheel_stack, sizeof(clickwheel_stack), OS_THREAD, 200, true, | 
| 157 | 166 | NULL, NULL, NULL, NULL); | 
|  | 167 | +    wakeup_wait(&clickwheel_init_wakeup, 100000); | 
|  | 168 | +    if (!wheel_initialized) RET_ERR(0); | 
|  | 169 | +    return 0; | 
| 158 | 170 | } | 
| 159 | 171 |  | 
| 160 | 172 | void INT_WHEEL(void) ICODE_ATTR; | 
| Index: emcore/trunk/target/ipodnano3g/targetinit.c | 
| — | — | @@ -37,6 +37,18 @@ | 
| 38 | 38 | int i; | 
| 39 | 39 |  | 
| 40 | 40 | clickwheel_init(); | 
|  | 41 | +    int buttons = clickwheel_get_state() & 0x1f; | 
|  | 42 | +    if (buttons == 0x11) | 
|  | 43 | +    { | 
|  | 44 | +        cputs(CONSOLE_BOOT, "MENU+SELECT is being pressed.\n" | 
|  | 45 | +                            "Continue pressing these buttons to enter DFU mode.\n"); | 
|  | 46 | +        while (buttons == 0x11) | 
|  | 47 | +        { | 
|  | 48 | +            sleep(100000); | 
|  | 49 | +            buttons = clickwheel_get_state() & 0x1f; | 
|  | 50 | +        } | 
|  | 51 | +        cputs(CONSOLE_BOOT, "MENU+SELECT was released. Continuing normal boot.\n"); | 
|  | 52 | +    } | 
| 41 | 53 |  | 
| 42 | 54 | uint8_t* nor = (uint8_t*)memalign(0x10, 0x1000); | 
| 43 | 55 | uint32_t* norword = (uint32_t*)nor; | 
| Index: emcore/trunk/target/ipodnano3g/clickwheel.c | 
| — | — | @@ -28,16 +28,23 @@ | 
| 29 | 29 | #include "timer.h" | 
| 30 | 30 | #include "s5l8702.h" | 
| 31 | 31 | #include "contextswitch.h" | 
|  | 32 | +#ifdef TARGET_ipodclassic | 
|  | 33 | +#include "fat.h" | 
|  | 34 | +#include "storage_ata.h" | 
|  | 35 | +#include "../ipodclassic/storage_ata-target.h" | 
|  | 36 | +#endif | 
| 32 | 37 |  | 
| 33 | 38 |  | 
| 34 | 39 | static struct wakeup clickwheel_wakeup IBSS_ATTR; | 
|  | 40 | +static struct wakeup clickwheel_init_wakeup INITDATA_ATTR; | 
| 35 | 41 | static volatile uint32_t clickwheel_packet IBSS_ATTR; | 
| 36 | 42 | static struct scheduler_thread clickwheel_thread_handle; | 
| 37 | 43 | static uint32_t clickwheel_stack[0x100] STACK_ATTR; | 
|  | 44 | +static bool wheel_initialized IBSS_ATTR; | 
| 38 | 45 | static bool oldtouched IBSS_ATTR; | 
| 39 | 46 | static int oldpos IBSS_ATTR; | 
| 40 | 47 | static int oldbuttons IBSS_ATTR; | 
| 41 |  | -static uint32_t lastpacket IBSS_ATTR;
 | 
|  | 48 | +static int lastpacket IBSS_ATTR; | 
| 42 | 49 | static int packets IBSS_ATTR; | 
| 43 | 50 | static int collect IBSS_ATTR; | 
| 44 | 51 | static int lastdiff IBSS_ATTR; | 
| — | — | @@ -55,14 +62,15 @@ | 
| 56 | 63 | uint32_t data = clickwheel_packet; | 
| 57 | 64 | leave_critical_section(mode); | 
| 58 | 65 | DEBUGF("Acquired clickwheel packet: %08X", data); | 
|  | 66 | +        int newbuttons = (data >> 8) & 0x1f; | 
| 59 | 67 | if ((data & 0x800000FF) == 0x8000001A) | 
| 60 | 68 | { | 
| 61 |  | -            int newbuttons = (data >> 8) & 0x1f;
 | 
| 62 | 69 | int newpos = (data >> 16) & 0xff; | 
| 63 | 70 | bool newtouched = (data & 0x40000000) ? true : false; | 
| 64 | 71 |  | 
| 65 | 72 | DEBUGF("This is a change packet, button state: %02X, position: %02d, touched: %d", | 
| 66 | 73 | newbuttons, newpos, newtouched); | 
|  | 74 | + | 
| 67 | 75 | int buttonschanged = oldbuttons ^ newbuttons; | 
| 68 | 76 | DEBUGF("Changed buttons: %02X", buttonschanged); | 
| 69 | 77 | for (i = 0; i < 5; i++) | 
| — | — | @@ -115,7 +123,6 @@ | 
| 116 | 124 | lastdiff = 0; | 
| 117 | 125 | } | 
| 118 | 126 |  | 
| 119 |  | -            oldbuttons = newbuttons;
 | 
| 120 | 127 | oldpos = newpos; | 
| 121 | 128 | oldtouched = newtouched; | 
| 122 | 129 | lastpacket = USEC_TIMER; | 
| — | — | @@ -122,16 +129,36 @@ | 
| 123 | 130 | } | 
| 124 | 131 | else if ((data & 0x8000FFFF) == 0x8000023A) | 
| 125 | 132 | { | 
| 126 |  | -            if (data & 0x1F0000) oldbuttons = (data >> 16) & 0x1F;
 | 
| 127 |  | -            DEBUGF("This is an init packet, button state: %02X", oldbuttons);
 | 
|  | 133 | +            if (data & 0x1F0000) newbuttons = (data >> 16) & 0x1F; | 
|  | 134 | +            DEBUGF("This is an init packet, button state: %02X", newbuttons); | 
|  | 135 | +            if (!wheel_initialized) | 
|  | 136 | +            { | 
|  | 137 | +                wheel_initialized = true; | 
|  | 138 | +                wakeup_signal(&clickwheel_init_wakeup); | 
|  | 139 | +            } | 
| 128 | 140 | } | 
|  | 141 | + | 
|  | 142 | +        #ifdef TARGET_ipodclassic | 
|  | 143 | +            if (newbuttons == 0x11 && oldbuttons != 0x11) | 
|  | 144 | +            { | 
|  | 145 | +                ata_lock_exclusive(TIMEOUT_BLOCK); | 
|  | 146 | +                flush_fat(true); | 
|  | 147 | +                ata_sleepnow(); | 
|  | 148 | +            } | 
|  | 149 | +            else if (newbuttons != 0x11 && oldbuttons == 0x11) | 
|  | 150 | +                ata_unlock_exclusive(); | 
|  | 151 | +#endif | 
|  | 152 | + | 
|  | 153 | +        oldbuttons = newbuttons; | 
| 129 | 154 | } | 
| 130 | 155 | } | 
| 131 | 156 |  | 
| 132 | 157 |  | 
| 133 |  | -void clickwheel_init()
 | 
|  | 158 | +int clickwheel_init() | 
| 134 | 159 | { | 
| 135 | 160 | wakeup_init(&clickwheel_wakeup); | 
|  | 161 | +    wakeup_init(&clickwheel_init_wakeup); | 
|  | 162 | +    wheel_initialized = false; | 
| 136 | 163 | oldtouched = false; | 
| 137 | 164 | oldbuttons = 0; | 
| 138 | 165 | lastpacket = 0; | 
| — | — | @@ -150,6 +177,9 @@ | 
| 151 | 178 | thread_create(&clickwheel_thread_handle, "Clickwheel dispatcher", clickwheel_thread, | 
| 152 | 179 | clickwheel_stack, sizeof(clickwheel_stack), OS_THREAD, 200, true, | 
| 153 | 180 | NULL, NULL, NULL, NULL); | 
|  | 181 | +    wakeup_wait(&clickwheel_init_wakeup, 100000); | 
|  | 182 | +    if (!wheel_initialized) RET_ERR(0); | 
|  | 183 | +    return 0; | 
| 154 | 184 | } | 
| 155 | 185 |  | 
| 156 | 186 | void INT_WHEEL(void) ICODE_ATTR; | 
| Index: emcore/trunk/clickwheel.h | 
| — | — | @@ -28,7 +28,7 @@ | 
| 29 | 29 | #include "global.h" | 
| 30 | 30 |  | 
| 31 | 31 |  | 
| 32 |  | -void clickwheel_init(void) INITCODE_ATTR;
 | 
|  | 32 | +int clickwheel_init(void) INITCODE_ATTR; | 
| 33 | 33 | uint32_t clickwheel_get_state(void); | 
| 34 | 34 |  | 
| 35 | 35 |  | 
| Index: emcore/trunk/fat.c | 
| — | — | @@ -182,7 +182,6 @@ | 
| 183 | 183 | static bool flush_fat_disabled = false; | 
| 184 | 184 |  | 
| 185 | 185 | static int update_fsinfo(IF_MV_NONVOID(struct bpb* fat_bpb)); | 
| 186 |  | -static int flush_fat(IF_MV_NONVOID(struct bpb* fat_bpb));
 | 
| 187 | 186 | static int bpb_is_sane(IF_MV_NONVOID(struct bpb* fat_bpb)); | 
| 188 | 187 | static void *cache_fat_sector(IF_MV2(struct bpb* fat_bpb,) | 
| 189 | 188 | long secnum, bool dirty); | 
| — | — | @@ -487,10 +486,11 @@ | 
| 488 | 487 | #else | 
| 489 | 488 | (void)volume; | 
| 490 | 489 | #endif | 
|  | 490 | +    if (!initialized) return; | 
| 491 | 491 |  | 
| 492 | 492 | if(flush) | 
| 493 | 493 | { | 
| 494 |  | -        rc = flush_fat(IF_MV(fat_bpb)); /* the clean way, while still alive */
 | 
|  | 494 | +        rc = flush_fat(IF_MV2(fat_bpb,) true); /* the clean way, while still alive */ | 
| 495 | 495 | } | 
| 496 | 496 | else | 
| 497 | 497 | {   /* volume is not accessible any more, e.g. MMC removed */ | 
| — | — | @@ -1024,12 +1024,12 @@ | 
| 1025 | 1025 | return 0; | 
| 1026 | 1026 | } | 
| 1027 | 1027 |  | 
| 1028 |  | -static int flush_fat(IF_MV_NONVOID(struct bpb* fat_bpb))
 | 
|  | 1028 | +int flush_fat(IF_MV2(struct bpb* fat_bpb,) bool force) | 
| 1029 | 1029 | { | 
| 1030 | 1030 | int i; | 
| 1031 | 1031 | int rc; | 
| 1032 | 1032 | unsigned char *sec; | 
| 1033 |  | -    if (flush_fat_disabled)
 | 
|  | 1033 | +    if (flush_fat_disabled && !force) | 
| 1034 | 1034 | { | 
| 1035 | 1035 | DEBUGF("flush_fat() skipped"); | 
| 1036 | 1036 | return 0; | 
| — | — | @@ -1780,7 +1780,7 @@ | 
| 1781 | 1781 | /* Set the firstcluster field in the direntry */ | 
| 1782 | 1782 | update_short_entry(&newdir, 0, FAT_ATTR_DIRECTORY); | 
| 1783 | 1783 |  | 
| 1784 |  | -    rc = flush_fat(IF_MV(fat_bpb));
 | 
|  | 1784 | +    rc = flush_fat(IF_MV2(fat_bpb,) false); | 
| 1785 | 1785 | if (rc < 0) | 
| 1786 | 1786 | return rc * 10 - 5; | 
| 1787 | 1787 |  | 
| — | — | @@ -1830,7 +1830,7 @@ | 
| 1831 | 1831 | return rc * 10 - 1; | 
| 1832 | 1832 | } | 
| 1833 | 1833 |  | 
| 1834 |  | -    flush_fat(IF_MV(fat_bpb));
 | 
|  | 1834 | +    flush_fat(IF_MV2(fat_bpb,) false); | 
| 1835 | 1835 |  | 
| 1836 | 1836 | #ifdef TEST_FAT | 
| 1837 | 1837 | if ( file->firstcluster ) { | 
| — | — | @@ -1968,7 +1968,7 @@ | 
| 1969 | 1969 | file->firstcluster = 0; | 
| 1970 | 1970 | file->dircluster = 0; | 
| 1971 | 1971 |  | 
| 1972 |  | -    rc = flush_fat(IF_MV(fat_bpb));
 | 
|  | 1972 | +    rc = flush_fat(IF_MV2(fat_bpb,) false); | 
| 1973 | 1973 | if (rc < 0) | 
| 1974 | 1974 | return rc * 10 - 2; | 
| 1975 | 1975 |  | 
| — | — | @@ -2017,7 +2017,7 @@ | 
| 2018 | 2018 | if (rc < 0) | 
| 2019 | 2019 | return rc * 10 - 4; | 
| 2020 | 2020 |  | 
| 2021 |  | -    rc = flush_fat(IF_MV(fat_bpb));
 | 
|  | 2021 | +    rc = flush_fat(IF_MV2(fat_bpb,) false); | 
| 2022 | 2022 | if (rc < 0) | 
| 2023 | 2023 | return rc * 10 - 5; | 
| 2024 | 2024 |  | 
| — | — | @@ -2575,5 +2575,5 @@ | 
| 2576 | 2576 | void fat_enable_flushing(bool state) | 
| 2577 | 2577 | { | 
| 2578 | 2578 | flush_fat_disabled = !state; | 
| 2579 |  | -    if (state) flush_fat();
 | 
|  | 2579 | +    if (state) flush_fat(true); | 
| 2580 | 2580 | } | 
| Index: emcore/trunk/fat.h | 
| — | — | @@ -142,6 +142,7 @@ | 
| 143 | 143 | extern bool fat_ismounted(int volume); | 
| 144 | 144 | extern void* fat_get_sector_buffer(void); | 
| 145 | 145 | extern void fat_release_sector_buffer(void); | 
|  | 146 | +extern int flush_fat(IF_MV2(struct bpb* fat_bpb,) bool force); | 
| 146 | 147 |  | 
| 147 | 148 |  | 
| 148 | 149 | #endif |