summaryrefslogtreecommitdiff
path: root/firmware/target
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/target
parent3c4fdf10e24d54ca0f11ca35eaf614126a476bb6 (diff)
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/target')
-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 @@
* ensure that removing the card always resets the driver to a sane state.
*/
+#define DEBOUNCE_TIME (HZ/10)
+
static const msc_config msc_configs[] = {
#ifdef FIIO_M3K
#define MSC_CLOCK_SOURCE X1000_CLK_SCLK_A
@@ -105,6 +107,7 @@ static void msc_init_one(msc_drv* d, int msc)
d->req = NULL;
d->iflag_done = 0;
d->card_present = 1;
+ d->card_present_last = 1;
d->req_running = 0;
mutex_init(&d->lock);
semaphore_init(&d->cmd_done, 1, 0);
@@ -122,8 +125,10 @@ static void msc_init_one(msc_drv* d, int msc)
/* Setup the card detect IRQ */
if(d->config->cd_gpio != GPIO_NONE) {
- if(gpio_get_level(d->config->cd_gpio) != d->config->cd_active_level)
+ if(gpio_get_level(d->config->cd_gpio) != d->config->cd_active_level) {
d->card_present = 0;
+ d->card_present_last = 0;
+ }
system_set_irq_handler(GPIO_TO_IRQ(d->config->cd_gpio),
msc == 0 ? msc0_cd_interrupt : msc1_cd_interrupt);
@@ -613,11 +618,25 @@ static void msc_interrupt(msc_drv* d)
static int msc_cd_callback(struct timeout* tmo)
{
msc_drv* d = (msc_drv*)tmo->data;
+ int now_present = msc_card_detect(d) ? 1 : 0;
+
+ /* If the CD pin level changed during the timeout interval, then the
+ * signal is not yet stable and we need to wait longer. */
+ if(now_present != d->card_present_last) {
+ d->card_present_last = now_present;
+ return DEBOUNCE_TIME;
+ }
- /* If card is still present we assume the card is properly inserted */
- if(msc_card_detect(d)) {
- d->card_present = 1;
- queue_broadcast(SYS_HOTSWAP_INSERTED, d->drive_nr);
+ /* If there is a change, then broadcast the hotswap event */
+ if(now_present != d->card_present) {
+ if(now_present) {
+ d->card_present = 1;
+ queue_broadcast(SYS_HOTSWAP_INSERTED, d->drive_nr);
+ } else {
+ msc_async_abort(d, MSC_REQ_EXTRACTED);
+ d->card_present = 0;
+ queue_broadcast(SYS_HOTSWAP_EXTRACTED, d->drive_nr);
+ }
}
return 0;
@@ -625,17 +644,9 @@ static int msc_cd_callback(struct timeout* tmo)
static void msc_cd_interrupt(msc_drv* d)
{
- if(!msc_card_detect(d)) {
- /* Immediately abort and notify when removing a card */
- msc_async_abort(d, MSC_REQ_EXTRACTED);
- if(d->card_present) {
- d->card_present = 0;
- queue_broadcast(SYS_HOTSWAP_EXTRACTED, d->drive_nr);
- }
- } else {
- /* Timer to debounce input */
- timeout_register(&d->cd_tmo, msc_cd_callback, HZ/4, (intptr_t)d);
- }
+ /* Timer to debounce input */
+ d->card_present_last = msc_card_detect(d) ? 1 : 0;
+ timeout_register(&d->cd_tmo, msc_cd_callback, DEBOUNCE_TIME, (intptr_t)d);
/* Invert the IRQ */
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 {
unsigned iflag_done;
volatile int req_running;
- volatile int card_present;
+ volatile int card_present; /* Debounced status */
+ volatile int card_present_last; /* Status when we last polled it */
struct mutex lock;
struct semaphore cmd_done;