/**************************************************************************** * boards/arm/samd5e5/metro-m4/src/sam_automount.c * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. The * ASF licenses this file to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance with the * License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. * ****************************************************************************/ /**************************************************************************** * Included Files ****************************************************************************/ #include #if defined(CONFIG_FS_AUTOMOUNTER_DEBUG) && !defined(CONFIG_DEBUG_FS) # define CONFIG_DEBUG_FS 1 #endif #include #include #include #include #include #include "metro-m4.h" #ifdef CONFIG_FS_AUTOMOUNTER /**************************************************************************** * Private Types ****************************************************************************/ /* This structure represents the changeable state of the automounter */ struct sam_automount_state_s { volatile automount_handler_t handler; /* Upper half handler */ void *arg; /* Handler argument */ bool enable; /* Fake interrupt enable */ bool pending; /* Set if there an event while disabled */ bool inserted; }; /* This structure represents the static configuration of an automounter */ struct sam_automount_config_s { /* This must be first thing in structure so that we can simply cast from * struct automount_lower_s to struct sam_automount_config_s */ struct automount_lower_s lower; /* Publicly visible part */ struct sam_automount_state_s *state; /* Changeable state */ }; /**************************************************************************** * Private Function Prototypes ****************************************************************************/ static int sam_attach(const struct automount_lower_s *lower, automount_handler_t isr, void *arg); static void sam_enable(const struct automount_lower_s *lower, bool enable); static bool sam_inserted(const struct automount_lower_s *lower); /**************************************************************************** * Private Data ****************************************************************************/ #ifdef CONFIG_METRO_M4_USB_AUTOMOUNT static struct sam_automount_state_s g_port0state; static const struct sam_automount_config_s g_port0config = { .lower = { .fstype = CONFIG_METRO_M4_USB_AUTOMOUNT_FSTYPE, .blockdev = CONFIG_METRO_M4_USB_AUTOMOUNT_BLKDEV, .mountpoint = CONFIG_METRO_M4_USB_AUTOMOUNT_MOUNTPOINT, .ddelay = MSEC2TICK(CONFIG_METRO_M4_USB_AUTOMOUNT_DDELAY), .udelay = MSEC2TICK(CONFIG_METRO_M4_USB_AUTOMOUNT_UDELAY), .attach = sam_attach, .enable = sam_enable, .inserted = sam_inserted }, .state = &g_port0state }; #endif /**************************************************************************** * Private Functions ****************************************************************************/ /**************************************************************************** * Name: sam_attach * * Description: * Attach a new port event handler * * Input Parameters: * lower - An instance of the auto-mounter lower half state structure * isr - The new event handler to be attach * arg - Client data to be provided when the event handler is invoked. * * Returned Value: * Always returns OK * ****************************************************************************/ static int sam_attach(const struct automount_lower_s *lower, automount_handler_t isr, void *arg) { const struct sam_automount_config_s *config; struct sam_automount_state_s *state; finfo("Entry\n"); /* Recover references to our structure */ config = (struct sam_automount_config_s *)lower; DEBUGASSERT(config && config->state); state = config->state; /* Save the new handler info (clearing the handler first to eliminate * race conditions). */ state->handler = NULL; state->pending = false; state->arg = arg; state->handler = isr; return OK; } /**************************************************************************** * Name: sam_enable * * Description: * Enable port insertion/removal event detection * * Input Parameters: * lower - An instance of the auto-mounter lower half state structure * enable - True: enable event detection; False: disable * * Returned Value: * None * ****************************************************************************/ static void sam_enable(const struct automount_lower_s *lower, bool enable) { const struct sam_automount_config_s *config; struct sam_automount_state_s *state; irqstate_t flags; finfo("Entry\n"); /* Recover references to our structure */ config = (struct sam_automount_config_s *)lower; DEBUGASSERT(config && config->state); state = config->state; /* Save the fake enable setting */ flags = enter_critical_section(); state->enable = enable; /* Did an interrupt occur while interrupts were disabled? */ if (enable && state->pending) { /* Yes.. perform the fake interrupt if the interrupt is attached */ if (state->handler) { state->handler(&config->lower, state->arg, true); } state->pending = false; } leave_critical_section(flags); } /**************************************************************************** * Name: sam_inserted * * Description: * Check if a card is inserted into the slot. * * Input Parameters: * lower - An instance of the auto-mounter lower half state structure * * Returned Value: * True if the card is inserted; False otherwise * ****************************************************************************/ static bool sam_inserted(const struct automount_lower_s *lower) { const struct sam_automount_config_s *config; config = (struct sam_automount_config_s *)lower; DEBUGASSERT(config && config->state); finfo("inserted:%d\n", config->state->inserted); return config->state->inserted; } /**************************************************************************** * Public Functions ****************************************************************************/ /**************************************************************************** * Name: sam_automount_initialize * * Description: * Configure auto-mounters for each enable and so configured HSMCI * * Input Parameters: * None * * Returned Value: * None * ****************************************************************************/ void sam_automount_initialize(void) { void *handle; finfo("Initializing automounter(s)\n"); #ifdef CONFIG_METRO_M4_USB_AUTOMOUNT /* Initialize the USB auto-mounter */ handle = automount_initialize(&g_port0config.lower); if (!handle) { ferr("ERROR: Failed to initialize auto-mounter for USB\n"); } #endif } /**************************************************************************** * Name: sam_automount_event * * Description: * It has already scheduled the MMC/SD block driver operations. * Now we need to schedule the auto-mount event which will occur with * a substantial delay to make sure that everything has settle down. * * Input Parameters: * inserted - True if the card is inserted in the slot. False otherwise. * * Returned Value: * None * * Assumptions: * Interrupts are disabled. * ****************************************************************************/ void sam_automount_event(bool inserted) { const struct sam_automount_config_s *config; struct sam_automount_state_s *state; #ifdef CONFIG_METRO_M4_USB_AUTOMOUNT config = &g_port0config; state = &g_port0state; state->inserted = inserted; #endif finfo("event:%d\n", inserted); /* Is the auto-mounter interrupt attached? */ if (state->handler) { /* Yes.. Have we been asked to hold off interrupts? */ if (!state->enable) { /* Yes.. just remember that there is a pending interrupt. * We will deliver the interrupt when interrupts are * "re-enabled." */ state->pending = true; } else { /* No.. forward the event to the handler */ state->handler(&config->lower, state->arg, state->inserted); } } } #endif /* CONFIG_FS_AUTOMOUNTER */