A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd

x1000: revamp MSC driver card detection logic

Debounce logic now handles both removal and insertion and verifies
the detection is stable for 100ms before taking any action.

This solves the bootloader "file not found" issue on the Shanling Q1.
It seems a false removal event was generated, causing the filesystem
to be automatically unmounted. Probably this is due to some transient
noise at boot. Delays didn't solve the problem, probably because the
bogus hotplug event was queued, and normal mdelay() would simply delay
event delivery.

Change-Id: I8b03fb3550309f5a7ab4be0be7465a3dab2d3450

+29 -17
+27 -16
firmware/target/mips/ingenic_x1000/msc-x1000.c
··· 39 39 * ensure that removing the card always resets the driver to a sane state. 40 40 */ 41 41 42 + #define DEBOUNCE_TIME (HZ/10) 43 + 42 44 static const msc_config msc_configs[] = { 43 45 #ifdef FIIO_M3K 44 46 #define MSC_CLOCK_SOURCE X1000_CLK_SCLK_A ··· 105 107 d->req = NULL; 106 108 d->iflag_done = 0; 107 109 d->card_present = 1; 110 + d->card_present_last = 1; 108 111 d->req_running = 0; 109 112 mutex_init(&d->lock); 110 113 semaphore_init(&d->cmd_done, 1, 0); ··· 122 125 123 126 /* Setup the card detect IRQ */ 124 127 if(d->config->cd_gpio != GPIO_NONE) { 125 - if(gpio_get_level(d->config->cd_gpio) != d->config->cd_active_level) 128 + if(gpio_get_level(d->config->cd_gpio) != d->config->cd_active_level) { 126 129 d->card_present = 0; 130 + d->card_present_last = 0; 131 + } 127 132 128 133 system_set_irq_handler(GPIO_TO_IRQ(d->config->cd_gpio), 129 134 msc == 0 ? msc0_cd_interrupt : msc1_cd_interrupt); ··· 613 618 static int msc_cd_callback(struct timeout* tmo) 614 619 { 615 620 msc_drv* d = (msc_drv*)tmo->data; 621 + int now_present = msc_card_detect(d) ? 1 : 0; 616 622 617 - /* If card is still present we assume the card is properly inserted */ 618 - if(msc_card_detect(d)) { 619 - d->card_present = 1; 620 - queue_broadcast(SYS_HOTSWAP_INSERTED, d->drive_nr); 623 + /* If the CD pin level changed during the timeout interval, then the 624 + * signal is not yet stable and we need to wait longer. */ 625 + if(now_present != d->card_present_last) { 626 + d->card_present_last = now_present; 627 + return DEBOUNCE_TIME; 628 + } 629 + 630 + /* If there is a change, then broadcast the hotswap event */ 631 + if(now_present != d->card_present) { 632 + if(now_present) { 633 + d->card_present = 1; 634 + queue_broadcast(SYS_HOTSWAP_INSERTED, d->drive_nr); 635 + } else { 636 + msc_async_abort(d, MSC_REQ_EXTRACTED); 637 + d->card_present = 0; 638 + queue_broadcast(SYS_HOTSWAP_EXTRACTED, d->drive_nr); 639 + } 621 640 } 622 641 623 642 return 0; ··· 625 644 626 645 static void msc_cd_interrupt(msc_drv* d) 627 646 { 628 - if(!msc_card_detect(d)) { 629 - /* Immediately abort and notify when removing a card */ 630 - msc_async_abort(d, MSC_REQ_EXTRACTED); 631 - if(d->card_present) { 632 - d->card_present = 0; 633 - queue_broadcast(SYS_HOTSWAP_EXTRACTED, d->drive_nr); 634 - } 635 - } else { 636 - /* Timer to debounce input */ 637 - timeout_register(&d->cd_tmo, msc_cd_callback, HZ/4, (intptr_t)d); 638 - } 647 + /* Timer to debounce input */ 648 + d->card_present_last = msc_card_detect(d) ? 1 : 0; 649 + timeout_register(&d->cd_tmo, msc_cd_callback, DEBOUNCE_TIME, (intptr_t)d); 639 650 640 651 /* Invert the IRQ */ 641 652 gpio_flip_edge_irq(d->config->cd_gpio);
+2 -1
firmware/target/mips/ingenic_x1000/msc-x1000.h
··· 126 126 unsigned iflag_done; 127 127 128 128 volatile int req_running; 129 - volatile int card_present; 129 + volatile int card_present; /* Debounced status */ 130 + volatile int card_present_last; /* Status when we last polled it */ 130 131 131 132 struct mutex lock; 132 133 struct semaphore cmd_done;