summaryrefslogtreecommitdiff
path: root/firmware
diff options
context:
space:
mode:
authorAidan MacDonald <amachronic@protonmail.com>2021-07-13 22:01:17 +0100
committerAidan MacDonald <amachronic@protonmail.com>2021-07-13 22:01:17 +0100
commit3abb7c5dd5be2ec6744bfc0a80967b20f1b59e30 (patch)
treeb96e54d218a3eaa4abe6fb99c6f74b926afeab60 /firmware
parent3c4fdf10e24d54ca0f11ca35eaf614126a476bb6 (diff)
downloadrockbox-3abb7c5dd5be2ec6744bfc0a80967b20f1b59e30.tar.gz
rockbox-3abb7c5dd5be2ec6744bfc0a80967b20f1b59e30.zip
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
Diffstat (limited to 'firmware')
-rw-r--r--firmware/target/mips/ingenic_x1000/msc-x1000.c43
-rw-r--r--firmware/target/mips/ingenic_x1000/msc-x1000.h3
2 files changed, 29 insertions, 17 deletions
diff --git a/firmware/target/mips/ingenic_x1000/msc-x1000.c b/firmware/target/mips/ingenic_x1000/msc-x1000.c
index 27929cced5..3b7df1dd01 100644
--- a/firmware/target/mips/ingenic_x1000/msc-x1000.c
+++ b/firmware/target/mips/ingenic_x1000/msc-x1000.c
@@ -39,6 +39,8 @@
39 * ensure that removing the card always resets the driver to a sane state. 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
42static const msc_config msc_configs[] = { 44static const msc_config msc_configs[] = {
43#ifdef FIIO_M3K 45#ifdef FIIO_M3K
44#define MSC_CLOCK_SOURCE X1000_CLK_SCLK_A 46#define MSC_CLOCK_SOURCE X1000_CLK_SCLK_A
@@ -105,6 +107,7 @@ static void msc_init_one(msc_drv* d, int msc)
105 d->req = NULL; 107 d->req = NULL;
106 d->iflag_done = 0; 108 d->iflag_done = 0;
107 d->card_present = 1; 109 d->card_present = 1;
110 d->card_present_last = 1;
108 d->req_running = 0; 111 d->req_running = 0;
109 mutex_init(&d->lock); 112 mutex_init(&d->lock);
110 semaphore_init(&d->cmd_done, 1, 0); 113 semaphore_init(&d->cmd_done, 1, 0);
@@ -122,8 +125,10 @@ static void msc_init_one(msc_drv* d, int msc)
122 125
123 /* Setup the card detect IRQ */ 126 /* Setup the card detect IRQ */
124 if(d->config->cd_gpio != GPIO_NONE) { 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 d->card_present = 0; 129 d->card_present = 0;
130 d->card_present_last = 0;
131 }
127 132
128 system_set_irq_handler(GPIO_TO_IRQ(d->config->cd_gpio), 133 system_set_irq_handler(GPIO_TO_IRQ(d->config->cd_gpio),
129 msc == 0 ? msc0_cd_interrupt : msc1_cd_interrupt); 134 msc == 0 ? msc0_cd_interrupt : msc1_cd_interrupt);
@@ -613,11 +618,25 @@ static void msc_interrupt(msc_drv* d)
613static int msc_cd_callback(struct timeout* tmo) 618static int msc_cd_callback(struct timeout* tmo)
614{ 619{
615 msc_drv* d = (msc_drv*)tmo->data; 620 msc_drv* d = (msc_drv*)tmo->data;
621 int now_present = msc_card_detect(d) ? 1 : 0;
622
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 }
616 629
617 /* If card is still present we assume the card is properly inserted */ 630 /* If there is a change, then broadcast the hotswap event */
618 if(msc_card_detect(d)) { 631 if(now_present != d->card_present) {
619 d->card_present = 1; 632 if(now_present) {
620 queue_broadcast(SYS_HOTSWAP_INSERTED, d->drive_nr); 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 return 0; 642 return 0;
@@ -625,17 +644,9 @@ static int msc_cd_callback(struct timeout* tmo)
625 644
626static void msc_cd_interrupt(msc_drv* d) 645static void msc_cd_interrupt(msc_drv* d)
627{ 646{
628 if(!msc_card_detect(d)) { 647 /* Timer to debounce input */
629 /* Immediately abort and notify when removing a card */ 648 d->card_present_last = msc_card_detect(d) ? 1 : 0;
630 msc_async_abort(d, MSC_REQ_EXTRACTED); 649 timeout_register(&d->cd_tmo, msc_cd_callback, DEBOUNCE_TIME, (intptr_t)d);
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 }
639 650
640 /* Invert the IRQ */ 651 /* Invert the IRQ */
641 gpio_flip_edge_irq(d->config->cd_gpio); 652 gpio_flip_edge_irq(d->config->cd_gpio);
diff --git a/firmware/target/mips/ingenic_x1000/msc-x1000.h b/firmware/target/mips/ingenic_x1000/msc-x1000.h
index 70f67a70d6..b7b05b859d 100644
--- a/firmware/target/mips/ingenic_x1000/msc-x1000.h
+++ b/firmware/target/mips/ingenic_x1000/msc-x1000.h
@@ -126,7 +126,8 @@ typedef struct msc_drv {
126 unsigned iflag_done; 126 unsigned iflag_done;
127 127
128 volatile int req_running; 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 struct mutex lock; 132 struct mutex lock;
132 struct semaphore cmd_done; 133 struct semaphore cmd_done;